1 回答

TA貢獻(xiàn)1824條經(jīng)驗(yàn) 獲得超5個(gè)贊
問(wèn)題是,你正在使用async,并await在forEach通話(huà),而這也不行,你期望的那樣。
該forEach方法并不真正關(guān)心回調(diào)函數(shù)的返回值(在本例中是getStats返回的 promise )。
你應(yīng)該承諾map的things數(shù)組,并使用Promise.all:
async function getThings (folder) {
const things = await fs.promises.readdir(folder);
const promises = things.map(thing => getStats(thing, folder));
return await Promise.all(promises);
}
請(qǐng)注意,這將“并行”執(zhí)行承諾,而不是按順序執(zhí)行。
如果您想一個(gè)接一個(gè)地依次執(zhí)行承諾,您可以“減少”承諾數(shù)組,或者使用傳統(tǒng)的循環(huán) ( for, for-of)。
編輯:
讓我試著澄清為什么在 forEach 中使用異步回調(diào)函數(shù)不起作用。
嘗試#1:脫糖:
在最初的例子中,我們有這樣的事情:
// ...
things.forEach(async (thing)=>{
await getStats(thing, folder);
});
// ...
如果我們將回調(diào)與 分開(kāi)forEach,我們有:
const callback = async (thing)=>{
await getStats(thing, folder);
};
things.forEach(callback);
如果我們“脫糖”異步函數(shù):
const callback = function (thing) {
return new Promise((resolve, reject) => {
try {
getStats(thing, folder).then(stat => /*do nothing*/);
} catch (err) {
reject(err);
}
resolve();
});
};
things.forEach(callback);
將函數(shù)標(biāo)記為async確保函數(shù)將始終返回一個(gè)承諾,無(wú)論其完成,如果函數(shù)在沒(méi)有明確返回值的情況下執(zhí)行,承諾將被解析undefined,如果它返回某個(gè)值,承諾將解析為它,最后,如果函數(shù)中的某些東西拋出,承諾將被拒絕。
正如您所看到的,問(wèn)題在于承諾沒(méi)有被任何東西等待,而且它們也沒(méi)有解決任何價(jià)值。放置在回調(diào)中的 await 實(shí)際上對(duì)值沒(méi)有任何作用,就像上面我正在做的.then那樣,對(duì)值沒(méi)有做任何事情。
嘗試 2:實(shí)現(xiàn)一個(gè)簡(jiǎn)單的forEach函數(shù):
function forEach(array, callback) {
for(const value of array) {
callback(value);
}
}
const values = [ 'a', 'b', 'c' ];
forEach(values, (item) => {
console.log(item)
});
上面的 forEach 是對(duì)Array.prototype.forEach方法的過(guò)度簡(jiǎn)化,只是為了展示它的結(jié)構(gòu),實(shí)際上調(diào)用回調(diào)函數(shù)是傳遞數(shù)組作為this值,傳遞三個(gè)參數(shù),當(dāng)前元素,當(dāng)前索引,再次是數(shù)組實(shí)例,但是我們明白了。
如果我們想實(shí)現(xiàn)一個(gè)async forEach函數(shù),我們必須等待回調(diào)調(diào)用:
const sleep = (time, value) => new Promise(resolve => setTimeout(resolve(value), time));
const values = [ { time: 300, value: 'a'}, { time: 200, value: 'b' }, {time: 100, value: 'c' } ];
async function forEachAsync(array, callback) {
for(const value of array) {
await callback(value);
}
}
(async () => {
await forEachAsync(values, async (item) => {
console.log(await sleep(item.time, item.value))
});
console.log('done');
})()
上面的forEachAsync函數(shù)將逐項(xiàng)迭代和等待,通常你不希望那樣,如果異步函數(shù)是獨(dú)立的,它們可以并行完成,就像我首先建議的那樣。
const sleep = (time, value) => new Promise(resolve => setTimeout(resolve(value), time));
const values = [ { time: 300, value: 'a'}, { time: 200, value: 'b' }, {time: 100, value: 'c' } ];
(async () => {
const promises = values.map(item => sleep(item.time, item.value));
const result = await Promise.all(promises);
console.log(result);
})()
正如您所看到的,即使 Promise 是并行執(zhí)行的,我們也會(huì)以與數(shù)組中的 Promise 相同的順序獲得結(jié)果。
但是這個(gè)例子和第一個(gè)的區(qū)別是這個(gè)只需要300ms(最長(zhǎng)的promise解析),第一個(gè)需要600ms(300ms + 200ms + 100ms)。
希望它使它更清楚。
添加回答
舉報(bào)