繁体   English   中英

使用promises运行异步函数

[英]Running asynchronous functions in series with promises

我试图使用promises串行运行多个异步任务。 每个任务应在上一个任务完成后立即运行。 这是我尝试的简化示例:

var order = [];
var tasks = [
    new Promise(resolve => {
        order.push(1);
        setTimeout(() => {
            order.push(2)
            resolve();
        }, 100);
    }),
    new Promise(resolve => {
        order.push(3);
        setTimeout(() => {
            order.push(4)
            resolve();
        }, 100);
    }),
    new Promise(resolve => {
        order.push(5);
        resolve();
    })
];

tasks.reduce((cur, next) => cur.then(next), Promise.resolve()).then(() => {
    console.log(order); // [ 1, 3, 5 ]
});
setTimeout(() => console.log(order), 200); // [ 1, 3, 5, 2, 4 ]

我希望回调函数中的order相等[ 1, 2, 3, 4, 5 ] 但是我得到了那些奇怪的结果( [ 1, 3, 5 ] then回调和延迟函数中的[1,3,5,2,4 [ 1, 3, 5, 2, 4 ] )。 我错过了什么?

当你写的东西像

new Promise(resolve => {
    order.push(1);
    setTimeout(() => {
        order.push(2)
        resolve();
    }, 100);
});

它立即执行,意味着它现在运行,并在0.1秒内解决。
不要紧,你写一个数组里面,功能仍然跑,现在 ,承诺返回的数组中的值。

换句话说,所有三个promise呼叫都是并行运行的,它们都会立即运行,相隔几毫秒,并且从现在开始在内部定时器的给定时间内解析!

如果你想运行一个接一个的承诺,他们必须以某种方式被包裹,使他们不立即运行,但每当他们被称为,例如像

var tasks = [
    _ => new Promise(resolve => {
            order.push(1);
            setTimeout(() => {
                order.push(2)
                resolve();
            }, 100);
    }),
    _ => new Promise(resolve => {
            order.push(3);
            setTimeout(() => {
                order.push(4)
                resolve();
            }, 100);
    }),
    _ => new Promise(resolve => {
            order.push(5);
            resolve();
    }),
];

(下划线是有效的ES2015匿名箭头功能简写)

其中每个数组值都是可以调用的匿名函数,并且在调用时,promise构造函数会运行并返回promise。

要以串行方式递归调用函数,递归函数调用是最简单的,当电流完成时调用下一个函数。

(function iterate(i) {
    tasks[i]().then(() => {          // when done
        if (tasks[++i]) iterate(i);  // call the next one
    });
})(0);

小提琴


编辑:

既然你有返回promises的函数,你也可以使用Array.reduce你已经在做的方式

tasks.reduce((cur, next) => cur.then(next), Promise.resolve()).then(() => {
    // all done, chain is complete !
});

你错过了,当你使用这个事实setTimeout的回调(即推24和日志order )将在事件循环的下一次迭代中执行,即下一个“滴答”。 而所有其他函数( Promise构造函数和reduce回调)都是立即执行的 ,即在当前的'tick'中执行。

var order = [];
var tasks = [
    new Promise(resolve => {
        order.push(1); // 1. callback executes immediately pushing 1 into order
        setTimeout(() => { // 2. setTimeout executes, pushing the callback into the event queue after 100ms
            order.push(2) // 8. callback executes, pushing 2 into order
            resolve();
        }, 100);
    }),
    new Promise(resolve => {
        order.push(3); // 3. callback executes immediately pushing 3 into order
        setTimeout(() => { // 4. setTimeout executes, pushing the callback into the event queue after 100ms
            order.push(4) // 9. callback executes, pushing 4 into order
            resolve();
        }, 100);
    }),
    new Promise(resolve => {
        order.push(5); // 5. callback executes immediately pushing 5 into order 
        resolve();
    })
];

console.log(order); // [ 1, 3, 5 ]    

// 6. reduce executes immediately, executes Promise.resolve which logs order and then loops through order and executes the callback everytime
tasks.reduce((cur, next) => cur.then(next), Promise.resolve()).then(() => {
    console.log(order); // [ 1, 3, 5 ]
});

setTimeout(() => {
    console.log(order); // 10. callback executes and logs order
}, 200); // 7. setTimeout executes, pushing the callback into the event queue after 200ms

只有步骤1到7发生之后,在执行所述回调之后,将执行推送到事件队列中的所有回调(通过setTimeout ),即推送到调用堆栈,清除事件队列并最终清除调用堆栈(步骤8) ,9和10)。

请注意,当调用堆栈为空时,只会从事件队列中弹出函数。

这是一种没有承诺且略显奇怪的做事方式,但似乎有效:

"use strict";
var order = [];
var i = 0;
function next(){
    if(tasks[++i]) tasks[i]()
}
var tasks = [
    function() {
        order.push(1);
        setTimeout(() => {
            order.push(2)
            next()
        }, 100);
    },
    function() {
        order.push(3);
        setTimeout(() => {
            order.push(4)
            next();
        }, 100);
   },
   function() {
        order.push(5);
        next()
        console.log(order)
    }
];

tasks[0]()

每个异步函数都有一个同步部分,该设置通向promise的(同步)返回。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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