簡體   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