承诺链中承诺之间的延迟
Posted
技术标签:
【中文标题】承诺链中承诺之间的延迟【英文标题】:Delays between promises in promise chain 【发布时间】:2017-04-26 01:16:39 【问题描述】:假设我正在使用以下代码连续运行几个 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 等等。因此,该函数以正确的顺序为数组中的每个元素调用一次。
如何确保每次调用 mySpecialFunction(item)
之间至少有 50 毫秒的延迟?
以正确的顺序执行 promise 很重要,mySpecialFunction
的执行时间每次都不同。
我猜同步睡眠会起作用,但我不打算在单独的线程中运行这段代码,所以它会导致浏览器中烦人的 ui 冻结。
我不确定 setTimer 是否可以用于此目的。我的意思是我不能延迟承诺的回报。
【问题讨论】:
这可能对bluebirdjs.com/docs/api/promise.delay.html有帮助 我已经看到了,但我没有使用蓝鸟。我正在使用本机承诺。 (ECMA6) 【参考方案1】:答案很好,但它们等待的时间太长,因为所有答案都等待实际操作是否已经花费了超过 50 毫秒。
您可以使用Promise.all
。
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
let parameterArr = ['a','b','c','d','e','f'];
parameterArr.reduce(function(promise, item)
return promise.then(function(result)
return Promise.all([delay(50), myPromise(item)]);
);
, Promise.resolve());
【讨论】:
比我快 37 秒 :-)【参考方案2】:我称之为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
);
【讨论】:
【参考方案3】:要获得至少 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());
【讨论】:
【参考方案4】:以下示例说明了如何实现不阻塞但等待指定时间段的承诺:
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())
【讨论】:
【参考方案5】:给你: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() 的结果。只有这样你才能链接承诺。
注意,我将其更改为 1000 毫秒延迟只是为了强调。
【讨论】:
【参考方案6】:因为这似乎是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
都无关紧要,在它运行传递的回调中的代码之前总会有至少 50 毫秒的延迟。
【讨论】:
【参考方案7】:这是我对延迟承诺序列的完整解决方案:
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);
);
它接收承诺数组和它们之间的超时延迟(毫秒)作为参数。
希望对你有帮助!
【讨论】:
以上是关于承诺链中承诺之间的延迟的主要内容,如果未能解决你的问题,请参考以下文章