[英]ES6 promises with timeout interval
我正在尝试将我的一些代码转换为承诺,但我无法弄清楚如何在承诺中链接一个新的承诺。
我的 promise 函数应该每隔一秒左右检查一次数组的内容,如果里面有任何项目应该解决。 否则它应该等待 1s 并再次检查等等。
function get(){
return new Promise((resolve) => {
if(c.length > 0){
resolve(c.shift());
}else{
setTimeout(get.bind(this), 1000);
}
});
}
let c = [];
setTimeout(function(){
c.push('test');
}, 2000);
这就是我希望我的 get() 承诺函数工作的方式,它应该在最多 2 或 3 秒后打印“测试”:
get().then((value) => {
console.log(value);
});
显然它不起作用,什么也没有打印
setTimeout
本身具有糟糕的链接和错误处理特性,因此请始终将其包装起来:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms)); function get(c) { if (c.length) { return Promise.resolve(c.shift()); } return wait(1000).then(() => get(c)); // try again } let c = []; get(c).then(val => console.log(val)); wait(2000).then(() => c.push('test'));
虽然您没有问,但为了他人的利益,这是async
/ await
大放异彩的绝佳案例:
const wait = ms => new Promise(r => setTimeout(r, ms)); async function get(c) { while (!c.length) { await wait(1000); } return c.shift(); } let c = []; get(c).then(val => console.log(val)); wait(2000).then(() => c.push('test'));
注意我们这次不需要Promise.resolve()
,因为async
函数隐式地做到了这一点。
问题是你的递归调用没有传递resolve
函数,所以else
分支永远不能调用resolve
。
解决此问题的一种方法是在 promise 的回调中创建一个闭包,以便递归调用可以访问与初始调用相同的resolve
变量get
。
function get() { return new Promise((resolve) => { function loop() { if (c.length > 0) { resolve(c.shift()); } else { setTimeout(loop, 1000); } } loop(); }); } let c = []; setTimeout(function() { c.push('test'); }, 2000); get().then(val => console.log(val));
在else
情况下,您永远不会解决该承诺。 get
可能会创建另一个,但它返回到无处。
你应该promisify您的异步函数( setTimeout
上的最低水平),然后只链中的承诺。 通过从then
回调中return
递归调用的结果,最终的 Promise 将使用相同的结果解析:
function delayAsync(time) {
return new Promise(resolve => {
setTimeout(resolve, time);
});
}
function get(c) {
if (c.length > 0){
return Promise.resolve(c.shift());
} else {
return delay(1000).then(() => {
return get(c); // try again
});
}
}
您需要的是轮询服务,它在进行承诺解析之前定期检查特定条件。 目前当你运行setTimeout(get.bind(this), 1000);
您正在创建 Promise 的新实例,而没有实际解析初始 Promise,因为您没有引用您创建的初始resolve
函数。
解决方法:
resolve
和reject
作为参数传递,例如setTimeout(HandlePromise, 1000, resolve, reject, param3, param4 ..);
设置超时API function get() { var handlerFunction = resolve => { if (c.length > 0) { resolve(c.shift()); } else { setTimeout(handlerFunction, 1000, resolve); } }; return new Promise(handlerFunction); } let c = []; setTimeout(function() { c.push("test"); }, 2000); get().then(value => { console.log(value); });
你可以试试这个解决方案。 由于 JS 需要释放自己来下载图像,我在异步函数和异步调用中使用 await 在延迟后唤醒 JS
private async onBeforeDoingSomething() : void {
await this.delay(1000);
console.log("All images are loaded");
}
private delay (ms : number = 500) : Promise<number> {
return new Promise((resolve,reject) => {
const t = setTimeout( () => this.areImgsLoaded(resolve), ms);
});
}
private async areImgsLoaded (resolve) {
let reload = false;
const img = document.querySelectorAll('img');
console.log("total of images: ",img.length);
for (let i = 0; i < img.length; i++){
if (!img[i]["complete"]) {
console.log("img not load yet");
reload = true;
break;
}
}
if (reload) {
await this.delay();
}
resolve();
}
使用setInterval
每秒检查一次。 运行这个脚本来理解。
let c = []; function get(){ return new Promise((resolve) => { var i = setInterval(function(){ if(c.length > 0){ resolve(c.shift()); clearInterval(i); } }, 1000); }); } setTimeout(function(){ c.push('test'); }, 2000); get().then((value) => { console.log(value); });
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.