繁体   English   中英

ES6 承诺超时间隔

[英]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函数。

解决方法:

  • 创建一个新的回调函数,您可以在承诺中引用它
  • 在 setTimeout 调用中将resolvereject作为参数传递,例如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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM