我相信这个问题在你的forEach
电话中_scan
.供参考,请参阅使用ES7驯服异步野兽的这篇文章:
但是,如果您尝试使用异步函数,那么您将得到一个更微妙的错误:
let docs = [{}, {}, {}]; // WARNING: this won't work docs.forEach(async function (doc, i) { await db.post(doc); console.log(i); }); console.log('main loop done');这将编译,但问题是这将打印出来:
main loop done 0 1 2
发生的事情是主要功能是提前退出,因为
await
它实际上是在子功能中.此外,这将同时执行每个承诺,这不是我们的意图.经验教训是:在异步函数中有任何函数时要小心.将
await
只会暂停其父功能,因此检查它在做什么,你真的觉得它在做什么.
所以forEach
调用的每次迭代都是并发运行的; 他们不是一次执行一个.只要匹配条件的条件i === keys.length - 1
完成_scan
,即使其他异步函数forEach
仍然在执行,也会解析并返回promise .
你需要更改forEach
为a map
来返回一个promises数组,你可以await*
从中返回_scan
(如果你想同时执行它们然后在它们全部完成后调用它们),或者在一个a-a执行它们-time如果您希望它们按顺序执行.
作为旁注,如果我正确读取它们,可以简化一些异步功能; 请记住,当await
一个async
函数调用返回一个值时,只需调用它就会返回另一个promise,并且从async
函数返回一个值与返回一个在非async
函数中解析为该值的promise相同.所以,例如,_get
可以是:
async _get(type, id) { var data = _json[id] = _json[id] || await this._api(type, id); console.log(data) if (isAsset(data)) { return data; } else if (isEntry(data)) { await this._scan(data); return data; } else { const error = 'Response is not entry/asset.'; console.log(error); throw error; } }
同样,_scan
可能是(假设您希望forEach
并发执行主体):
async _scan(data) { if (data && data.fields) { const keys = Object.keys(data.fields); const promises = keys.map(async (key, i) => { var val = data.fields[key]; if (isLink(val)) { var child = await this._get(val.sys.linkType.toUpperCase(), val.sys.id); this._inject(data.fields, key, undefined, child); } else if (isLinkArray(val)) { var children = await* val.map(async (link) => await this._get(link.sys.linkType.toUpperCase(), link.sys.id)); children.forEach((child, index) => { this._inject(data.fields, key, index, child); }); } else { await new Promise((resolve) => setTimeout(resolve, 0)); } }); await* promises; } else { const error = 'Required data is unavailable.'; console.log(error); throw error; } }