次のコードを使用して、2つのPromiseを連続して実行するとします。
_let paramerterArr = ['a','b','c','d','e','f']
parameterArr.reduce(function(promise, item) {
return promise.then(function(result) {
return mySpecialFunction(item);
})
}, Promise.resolve())
_
コードは単にmySpecialFunction(promiseを返す)を呼び出し、promiseが解決されるのを待ってから、再びmySpecialFunctionを呼び出します。したがって、関数は配列内のすべての要素に対して正しい順序で1回呼び出されます。
mySpecialFunction(item)
の呼び出しごとに少なくとも50ミリ秒の遅延があることを確認するにはどうすればよいですか?
Promiseが正しい順序で実行され、mySpecialFunction
の実行時間が毎回異なることが重要です。
同期スリープは機能すると思いますが、このコードを別のスレッドで実行する予定はないので、ブラウザで迷惑なuiフリーズが発生します。
SetTimerが何らかの方法でこれに使用できるかどうかはわかりません。約束の返却を遅らせることはできません。
回答は良いですが、すべての回答が実際の操作に既に50ミリ秒以上かかったかどうかのに関係なく待機するため、待機時間が長すぎます。
Promise.all
を使用できます。
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
let paramerterArr = ['a','b','c','d','e','f']
parameterArr.reduce(function(promise, item) {
return promise.then(function(result) {
return Promise.all([delay(50), mySpecialFunction(item)]);
})
}, Promise.resolve())
便利なユーティリティ関数は、delay()
と呼んでいます。
function delay(t, val) {
return new Promise(function(resolve) {
if (t <= 0) {
resolve(val);
} else {
setTimeout(resolve.bind(null, val), t);
}
});
}
その後、次のようなプロミスチェーンで使用できます。
let paramerterArr = ['a','b','c','d','e','f']
parameterArr.reduce(function(promise, item, index) {
return promise.then(function(result) {
// no delay on first iteration
var delayT = index ? 50 : 0;
return delay(delayT, item).then(mySpecialFunction);
})
}, Promise.resolve());
オプションの遅延を使用して順次反復を実行するための小さなユーティリティ関数を作成することもできます。
// delayT is optional (defaults to 0)
function iterateSerialAsync(array, delayT, fn) {
if (!fn) {
fn = delayT;
delayT = 0;
}
array.reduce(function(p, item, index) {
return p.then(function() {
// no delay on first iteration
if (index === 0) delayT = 0;
return delay(delayT, item).then(fn)
});
}, Promise.resolve());
}
そして、あなたはそれをこのように使うでしょう:
iterateSerialAsync(paramerterArr, 50, mySpecialFunction).then(function(finalVal) {
// all done here
});
少なくとも 50msの遅延を取得するには、Promise.all
を使用します。
function delay(t) {
return new Promise(function(resolve) {
setTimeout(resolve, t);
});
}
parameterArr.reduce(function(promise, item) {
return promise.then(function() {
return Promise.all([
mySpecialFunction(item),
delay(50)
]);
});
}, Promise.resolve());
ここに行きます: https://jsbin.com/suvasox/edit?html,js,console
let paramerterArr = ['a','b','c','d','e','f']
paramerterArr.reduce((p, val) => {
return p.then(() => {
return new Promise((res) => {
setTimeout(() => { res(mySpecialFunction(val)); }, 1000);
});
});
}, Promise.resolve());
pはp.then()の結果でなければなりません。その方法でのみ、約束を連鎖させます。
強調のために、1000msの遅延に変更しました。
以下は、ブロックせずに指定された期間待機するプロミスを実現する方法の例を示しています。
function timedPromise(ms, payload) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(payload);
}, ms);
})
}
var time = Date.now();
timedPromise(1000)
.then(function() {
console.log(time - Date.now());
return timedPromise(2000);
}).then(function() {
console.log(time - Date.now());
return timedPromise(3000);
});
したがって、正確に何をしたいかに応じて、次のようなことができるはずです。
let paramerterArr = ['a','b','c','d','e','f']
parameterArr.reduce(function(promise, item) {
return promise.then(function(result) {
return mySpecialFunction(item);
}).then(function(specialResult) {
return timedPromise(50, specialResult);
});
}, Promise.resolve())
遅延されたプロミスシーケンスの完全なソリューションは次のとおりです。
function timeout_sequence_promise(promises = [], timeout = 200) {
//fake promise used as buffer between promises from params
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
//we need to create array of all promises with delayed buffers
let delayed_promises = [];
let total = promises.length;
let current = 0;
//every odd promise will be buffer
while (current < total) {
delayed_promises.Push(promises[current]);
delayed_promises.Push(delay(timeout));
current++;
}
return Promise.all(delayed_promises).then((result) => {
//we need to filter results from empty odd promises
return result.filter((item, index) => (index+2)%2 === 0);
});
}
パラメータとして、約束の配列とそれらの間のミリ秒単位のタイムアウト遅延を受け取ります。
よろしくお願いいたします。
これはmySpecialFunction
の要件であると思われるので、ここで実装します。つまり、最後の呼び出しから50ミリ秒以内に呼び出された場合、関数はそれ自体を遅延させます。
const delayBetweenCalls = (delay, fn) => {
let lastCall = NaN;
return function(/*...arguments*/){
//this and arguments are both forwarded to fn
return new Promise(resolve => {
let poll = () => {
let delta = Date.now() - lastCall;
if(delta < delay){
setTimeout(poll, delta - delay);
}else{
lastCall = Date.now();
resolve( fn.apply(this, arguments) );
}
}
poll();
})
}
}
次に:
const mySpecialFunction = delayBetweenCalls(50, function(some, ...args){
return someValueOrPromise;
});
//and your loop stays the same:
parameterArr.reduce(function(promise, item) {
return promise.then(function(result) {
return mySpecialFunction(item);
})
}, Promise.resolve())
したがって、mySpecialFunction
がどこでどのように呼び出されたかは関係ありません。渡されたコールバック内でコードを実行する前に、常に少なくとも50msの遅延があります。