[英]Node.js - Await for all the promises thrown inside a loop
我正在處理Node.js中的循環,它為循環的每次迭代執行兩個任務。 為簡化起見,代碼總結如下:
保存操作( 2
)將在數據庫中執行大約800個操作,並且不需要阻止主線程(我仍然可以從網頁中提取產品元數據)。
所以,正如所說,等待產品被保存沒有任何意義。 但是如果我在沒有等待它們的情況下拋出promise,則在循環的最后一次迭代中,Node.js進程退出並且所有未決操作都沒有完成。
哪種解決方法最好? 是否有可能在沒有完成承諾或發射器的計數器的情況下實現它? 謝謝。
for (let shop of shops) {
// 1
const products = await extractProductsMetadata(shop);
// 2
await saveProductsMetadata(products);
}
收集數組中的promises,然后在其上使用Promise.all
:
const storePromises = [];
for (let shop of shops) {
const products = await extractProductsMetadata(shop); //(1)
storePromises.push(saveProductsMetadata(products)); //(2)
}
await Promise.all(storePromises);
// ... all done (3)
通過(1)將一個接一個地運行,(2)將並行運行,(3)將在之后運行。
當然,您也可以並行運行(1)和(2):
await Promise.all(shops.map(async shop => {
const products = await extractProductsMetadata(shop); //(1)
await saveProductsMetadata(products);
}));
如果其中一個承諾發生錯誤,您可以使用try / catch
塊處理該錯誤,以確保所有其他商店不會受到影響:
await Promise.all(shops.map(async shop => {
try {
const products = await extractProductsMetadata(shop); //(1)
await saveProductsMetadata(products);
} catch(error) {
// handle it here
}
}));
如何通知節點完成該過程?
你可以手動調用process.exit(0);
,但這隱藏了真正的問題:如果沒有連接偵聽器, NodeJS會自動退出。 這意味着您應該在上面的代碼完成后關閉所有數據庫連接/服務器/等。
我們正在創建要處理的數據包。 當我們處理數據時,我們會同步執行所有get,並且異步保存所有內容。
我沒有處理失敗部分,我讓你添加它。 適當的try/catch
或函數封裝會做到這一點。
/**
* Call the given functions that returns promises in a queue
* options = context/args
*/
function promiseQueue(promisesFuncs, options = {}, _i = 0, _ret = []) {
return new Promise((resolve, reject) => {
if (_i >= promisesFuncs.length) {
return resolve(_ret);
}
// Call one
(promisesFuncs[_i]).apply(options.context || this, options.args || [])
.then((ret: any) => promiseQueue(promisesFuncs, _i + 1, options, [
..._ret,
ret,
]))
.then(resolve)
.catch(reject);
});
}
function async executePromiseAsPacks(arr, packSize, _i = 0) {
const toExecute = arr.slice(_i * packSize, packSize);
// Leave if we did execute all packs
if (toExecute.length === 0) return true;
// First we get all the data synchronously
const products = await promiseQueue(toExecute.map(x => () => extractProductsMetadata(x)));
// Then save the products asynchronously
// We do not put await here so it's truly asynchronous
Promise.all(toExecute.map((x, xi) => saveProductsMetadata(products[xi])));
// Call next
return executePromiseAsPacks(arr, packSize, _i + 1);
}
// Makes pack of data to treat (we extract synchronously and save asynchronously)
// Made to handle huge dataset
await executePromisesAsPacks(shops, 50);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.