簡體   English   中英

Promise 數組和異步函數的問題

[英]Troubles with promise array and async functions

我試圖使用異步函數來實現 Promise.all 函數。 但是當其中一個承諾被拒絕時,我得到一個錯誤。 這是我所做的實現:

    async function Promise_All_II(promises){
        let results = []
        for(let p of promises)
            results.push(await p)
        return results
    }

    const takeTime = (value, time=1000) => new Promise(resolve => setTimeout(resolve, time, value))

    let promises = [
        Promise.resolve(1),
        takeTime(2),
        Promise.reject('You are fairly dump'),
        takeTime(3)
    ]
    
    console.log('Promise all II:')
    Promise_All_II(promises).then(console.log, console.log)

這是當其中一個承諾被拒絕時我得到的錯誤:

Promise all II:
(node:9399) UnhandledPromiseRejectionWarning: You are fairly dump
(node:9399) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:9399) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
You are fairly dump
(node:9399) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)

我試圖用 try-catch 包裝for 循環,但它沒有用。 我還嘗試在p之后放置和.catch ,但仍然沒有用。

我注意到當您嘗試執行以下操作時會發生相同的錯誤:

let f = async () => {
    let ps = [
        Promise.resolve(10),
        Promise.reject(10),
        Promise.resolve(11),
        Promise.resolve(12)
    ]
    for(let p of ps)
        await p
}

f().catch(v => 
    console.log('something happened')
)

有人能幫助我嗎?

在 nodejs 中,當解釋器返回事件循環時,如果您將被拒絕的 Promise 留在沒有.catch()處理程序的地方,您將收到有關未處理拒絕的錯誤。 這意味着您不能在await某個其他承諾時將被拒絕的承諾留在變量中。 這將觸發未處理的拒絕錯誤。 JS 解釋器不夠聰明,無法知道您稍后會收到拒絕。

所以,當你這樣做時:

results.push(await p)

並且,任何其他 Promise 被拒絕,您將得到未處理的拒絕,因為被拒絕的 Promise 在它拒絕時沒有處理程序來處理拒絕,並且await會導致解釋器返回事件循環。 解釋器看到你處於空閑狀態,一個承諾被拒絕並且它沒有拒絕處理程序,從而觸發錯誤。

因此,由於未處理的拒絕在 nodejs 中的工作方式,實際上沒有辦法像您嘗試使用awaitfor循環那樣實現這一點,因為這使得其他承諾在await期間沒有拒絕處理程序。

Promise.all()的通常實現包括創建您自己的 Promise 並使用計數器來跟蹤所有問題何時解決。 而且,您會立即在每個 Promise 上安裝 resolve 和 reject 處理程序,這樣它們就不會處於導致未處理的拒絕處理程序的狀態。

這是Promise.all()的簡單實現,您可以在此代碼段中運行它:

 function Promise_All_II(promises) { return new Promise((resolve, reject) => { let cntr = 0; let length = 0; let results; for (let p of promises) { // keep track of index, for later use with result let i = length++; Promise.resolve(p).then(val => { results[i] = val; ++cntr; if (cntr === length) { resolve(results); } }).catch(reject); } if (length === 0) { resolve([]); return; } results = new Array(length); }); } const takeTime = (value, time=1000) => new Promise(resolve => setTimeout(resolve, time, value)) let promises = [ Promise.resolve(1), takeTime(2), Promise.reject('You are fairly dump'), takeTime(3) ]; console.log('Promise all II:') Promise_All_II(promises).then(console.log, console.log);

這會立即在每個 Promise 上安裝 resolve 和 reject 處理程序,從而避免未處理的拒絕錯誤。

注意, Promise_All_II()的調用者還必須有一個拒絕處理程序。


需要注意的幾個細節:

  1. 這適用於任何可迭代的,而不僅僅是按照Promise.all()規范的數組。 它甚至不必具有.length屬性。
  2. 根據Promise.all()規范,這實現了“快速拒絕”(例如,一旦任何承諾拒絕就拒絕)。
  3. 根據Promise.all()規范,這允許非承諾值在可迭代中。 這就是我們使用Promise.resolve(p).then(...)的原因,因此任何普通值都會被包裝,然后我們可以將其視為承諾。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM