並行調用異步/等待功能

據我瞭解,在ES7 / ES2016中,在代碼中放置多個await的工做方式相似於將帶有.then()的承諾連接在一塊兒,這意味着它們將一個接一個地執行而不是並行執行。 所以,例如,咱們有如下代碼: node

await someCall();
await anotherCall();

我是否正確理解只有在someCall()完成後纔會調用anotherCall() ? 並行調用它們的最優雅方式是什麼? chrome

我想在Node中使用它,因此也許有一個異步庫解決方案? promise

編輯:我不滿意此問題提供的解決方案: 減速是因爲異步生成器中非並行等待promise ,由於它使用生成器,而且我詢問的是更通用的用例。 瀏覽器


#1樓

您能夠在Promise.all()上等待: 異步

await Promise.all([someCall(), anotherCall()]);

要存儲結果: async

let [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);

#2樓

TL; DR ide

使用Promise.all進行並行函數調用時,發生錯誤時答案行爲不正確。 函數


首先,一次執行全部異步調用並獲取全部Promise對象。 其次,對Promise對象使用await 。 這樣,當您等待第一個Promise解決其餘異步調用時,仍在進行中。 整體而言,您只會等待最慢的異步調用時間。 例如: this

// Begin first call and store promise without waiting
const someResult = someCall();

// Begin second call and store promise without waiting
const anotherResult = anotherCall();

// Now we await for both results, whose async processes have already been started
const finalResult = [await someResult, await anotherResult];

// At this point all calls have been resolved
// Now when accessing someResult| anotherResult,
// you will have a value instead of a promise

JSbin示例: http ://jsbin.com/xerifanima/edit?js,console spa

注意: await調用是在同一行仍是在不一樣的行上都沒有關係,只要第一個await調用發生全部異步調用以後。 請參閱JohnnyHK的評論。


更新:這個回答有錯誤不一樣時間處理根據@ BERGI的答案 ,如發生錯誤時不會拋出了錯誤,但全部的承諾都執行以後。 我將結果與[result1, result2] = Promise.all([async1(), async2()])的技巧進行比較: [result1, result2] = Promise.all([async1(), async2()]) ,檢查如下代碼片斷

const correctAsync500ms = () => { return new Promise(resolve => { setTimeout(resolve, 500, 'correct500msResult'); }); }; const correctAsync100ms = () => { return new Promise(resolve => { setTimeout(resolve, 100, 'correct100msResult'); }); }; const rejectAsync100ms = () => { return new Promise((resolve, reject) => { setTimeout(reject, 100, 'reject100msError'); }); }; const asyncInArray = async (fun1, fun2) => { const label = 'test async functions in array'; try { console.time(label); const p1 = fun1(); const p2 = fun2(); const result = [await p1, await p2]; console.timeEnd(label); } catch (e) { console.error('error is', e); console.timeEnd(label); } }; const asyncInPromiseAll = async (fun1, fun2) => { const label = 'test async functions with Promise.all'; try { console.time(label); let [value1, value2] = await Promise.all([fun1(), fun2()]); console.timeEnd(label); } catch (e) { console.error('error is', e); console.timeEnd(label); } }; (async () => { console.group('async functions without error'); console.log('async functions without error: start') await asyncInArray(correctAsync500ms, correctAsync100ms); await asyncInPromiseAll(correctAsync500ms, correctAsync100ms); console.groupEnd(); console.group('async functions with error'); console.log('async functions with error: start') await asyncInArray(correctAsync500ms, rejectAsync100ms); await asyncInPromiseAll(correctAsync500ms, rejectAsync100ms); console.groupEnd(); })();


#3樓

我投同意票:

await Promise.all([someCall(), anotherCall()]);

請注意調用函數的那一刻,它可能會致使意外的結果:

// Supposing anotherCall() will trigger a request to create a new User

if (callFirst) {
  await someCall();
} else {
  await Promise.all([someCall(), anotherCall()]); // --> create new User here
}

可是跟隨老是觸發建立新用戶的請求

// Supposing anotherCall() will trigger a request to create a new User

const someResult = someCall();
const anotherResult = anotherCall(); // ->> This always creates new User

if (callFirst) {
  await someCall();
} else {
  const finalResult = [await someResult, await anotherResult]
}

#4樓

更新:

原始答案很難(在某些狀況下是不可能)正確處理承諾拒絕。 正確的解決方案是使用Promise.all

const [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);

原始答案:

只需確保在等待其中一個函數以前調用這兩個函數:

// Call both functions
const somePromise = someCall();
const anotherPromise = anotherCall();

// Await both promises    
const someResult = await somePromise;
const anotherResult = await anotherPromise;

#5樓

我建立了一個輔助函數waitAll,可能會使它更甜。 目前,它僅適用於nodejs不適用於瀏覽器chrome。

//const parallel = async (...items) => {
    const waitAll = async (...items) => {
        //this function does start execution the functions
        //the execution has been started before running this code here
        //instead it collects of the result of execution of the functions

        const temp = [];
        for (const item of items) {
            //this is not
            //temp.push(await item())
            //it does wait for the result in series (not in parallel), but
            //it doesn't affect the parallel execution of those functions
            //because they haven started earlier
            temp.push(await item);
        }
        return temp;
    };

    //the async functions are executed in parallel before passed
    //in the waitAll function

    //const finalResult = await waitAll(someResult(), anotherResult());
    //const finalResult = await parallel(someResult(), anotherResult());
    //or
    const [result1, result2] = await waitAll(someResult(), anotherResult());
    //const [result1, result2] = await parallel(someResult(), anotherResult());
相關文章
相關標籤/搜索