2017-09-15 69 views
0

我有以下功能。它獲得一組屬性,並將循環遍歷它們以將每個屬性放入數據庫中。但循環將與await聲明自動殺:爲什麼要「等待」在現代Javascript中打破或殺死for循環?

async function importAttributeRecords(attributeValues, languageId, attributes, dataStorage, tx) { 
    for(let attr of attributes) { 
    console.log("Persist", attr) 
    try { 
     await importAttributeRecord(attributeValues, languageId, attr, dataStorage, tx) 
    } 
    catch(err) { 
     console.log(err); 
    } 
    console.log("After persisting"); 
    } 
} 

await的第一次調用將被執行,但之後的第二console.log聲明將不會出現。 此外,循環將立即退出。

即使返回承諾,如何在同一個循環中同步執行像importAttributeRecord()這樣的函數? 爲什麼使用「等待」循環危險?

+0

你的意思是跟第二個日誌調用一個輸出:''在保持後''?拋出異常嗎? – k0pernikus

+4

需要更多[mcve]。 – melpomene

+4

循環未被殺死。它被擱置,當你「等待」承諾時會恢復。承諾是異步的。您不能將它們視爲同步。 –

回答

1

這可以被描述爲「類別錯誤」。一個for循環基本上是一個同步編程的想法,一個接一個地等待每個事物(通常是)一個數組或其他索引實體內的每個事物。

異步編程,async實現,是一種不同的方法。使用它的最完美的方式只是表達前情景和後情景之間的關係,並讓語言考慮時機並可能同時或並行執行。

對於這種情況,這裏是你會怎麼做:

async function importAttributeRecords(attributeValues, languageId, attributes, dataStorage, tx) { 
    return Promise.all(attributes.map(attr => { 
    console.log("Initiate persist", attr); 
    return importAttributeRecord(attributesValues, languageId, attr, dataStorage, tx).then(result => { 
     console.log("After persisting", attr, result); 
    }).catch(err => { 
     console.log("Error: ", attr, err); 
    })); 
    }); 
} 

你會注意到,現在importAttributeRecords承諾返回一個數組,所以它是合法async。你也會看到這段代碼稍微短一點!

+0

1.本例中沒有任何內容等待「importAttributeRecord」的承諾。你忘了'Promise.all'嗎? 2.問題中的代碼沒有問題。在循環中使用'await'可能不會被建議,因爲它將以串行方式運行,但這並不意味着它不起作用。無論打破OPs代碼將會破壞你的代碼。 'for'循環基本上是_serial_,但它不是基本上_synchronous_。 – loganfsmyth

+0

@loganfsmyth 1.誰說這個調用者不想使用'Promise.race'?你忘記了這種可能性嗎?另外,你是否在說你認爲返回'.then'的結果不是慣用的,並且與'async'兼容? 2.你是否在說你認爲* serial *與* asynchronous *是慣用的? –

+1

「誰說這個調用者不想使用Promise.race」因爲原始問題有一個循環,非常清楚地執行每個項目,等待它們全部。我的觀點是'return attributes.map('返回一個承諾數組,沒有等待它們中的任何一個完成,原始代碼非常明確地只在所有承諾完成後才從函數返回。2.在你的問題中,你說「for循環根本上是一個同步編程的想法」,這是不正確的,我的觀點是循環定義了排序行爲,代碼可以獨立於循環使用而同步或異步執行 – loganfsmyth