简体   繁体   English

使用promises运行异步函数

[英]Running asynchronous functions in series with promises

I am trying to run multiple asynchronous tasks in series using promises. 我试图使用promises串行运行多个异步任务。 Each task should run right after the previous one finishes. 每个任务应在上一个任务完成后立即运行。 This is simplified example what I have tried: 这是我尝试的简化示例:

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 ]

I would expect order to be equal [ 1, 2, 3, 4, 5 ] in the callback function. 我希望回调函数中的order相等[ 1, 2, 3, 4, 5 ] However I got those strange results ( [ 1, 3, 5 ] in then callback and [ 1, 3, 5, 2, 4 ] in delayed function). 但是我得到了那些奇怪的结果( [ 1, 3, 5 ] then回调和延迟函数中的[1,3,5,2,4 [ 1, 3, 5, 2, 4 ] )。 What am I missing? 我错过了什么?

When you write something like 当你写的东西像

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

it's executed right away, meaning it runs now , and resolves in 0.1 seconds. 它立即执行,意味着它现在运行,并在0.1秒内解决。
It doesn't matter that you write it inside an array, the functions are still ran right now , and the promises are returned as the values in the array. 不要紧,你写一个数组里面,功能仍然跑,现在 ,承诺返回的数组中的值。

In other words, all three promise calls run in parallell, they all run right away, with just milliseconds apart, and resolve at the given timen in the internal timer, from now ! 换句话说,所有三个promise呼叫都是并行运行的,它们都会立即运行,相隔几毫秒,并且从现在开始在内部定时器的给定时间内解析!

If you want to run one promise after the other, they have to somehow be wrapped so they don't run now , but whenever they are called, for instance something like 如果你想运行一个接一个的承诺,他们必须以某种方式被包裹,使他们不立即运行,但每当他们被称为,例如像

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();
    }),
];

(the underscore is valid ES2015 shorthand for an anonymous arrow function) (下划线是有效的ES2015匿名箭头功能简写)

where each array value is an anonymous function that can be called, and when called the promise constructor runs and returns the promise. 其中每个数组值都是可以调用的匿名函数,并且在调用时,promise构造函数会运行并返回promise。

To recursively call the functions in serial, a recursive function call is the easiest, where the next function is called when the current is finished etc. 要以串行方式递归调用函数,递归函数调用是最简单的,当电流完成时调用下一个函数。

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

FIDDLE 小提琴


Edit: 编辑:

You could also Array.reduce the way you're already doing it, now that you have functions that returns promises 既然你有返回promises的函数,你也可以使用Array.reduce你已经在做的方式

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

You're missing the fact that when you're using setTimeout , the callbacks (that push 2 , 4 and log order ) will be executed on the next iteration of the event loop , ie the next 'tick'. 你错过了,当你使用这个事实setTimeout的回调(即推24和日志order )将在事件循环的下一次迭代中执行,即下一个“滴答”。 While all other functions (the Promise constructors and the reduce callback) are being executed immediately , ie in the current 'tick'. 而所有其他函数( 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

Only After steps 1 through 7 happen, all callbacks that where pushed into the event queue (by setTimeout ) will be executed, ie pushed on the call stack, clearing the event queue and eventually clearing the call stack, after said callbacks execute (steps 8, 9 and 10). 只有步骤1到7发生之后,在执行所述回调之后,将执行推送到事件队列中的所有回调(通过setTimeout ),即推送到调用堆栈,清除事件队列并最终清除调用堆栈(步骤8) ,9和10)。

Note that functions are only popped off the event queue when the call stack is empty. 请注意,当调用堆栈为空时,只会从事件队列中弹出函数。

This is a promise-less and slightly strange way of doing things, but it seems to work: 这是一种没有承诺且略显奇怪的做事方式,但似乎有效:

"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