Arr*_*ght 8 node.js reactjs webpack babeljs ecmascript-next
我遇到了一个我不完全理解的问题.我觉得有可能是我没有掌握的概念,可以优化的代码,以及可能出现的错误.
大大简化整体流程:
这是原始请求(#1):
await Store.get(Constants.Contentful.ENTRY, Contentful[page.file])
Run Code Online (Sandbox Code Playgroud)
Store.get表示为:
async get(type, id) {
return await this._get(type, id);
}
Run Code Online (Sandbox Code Playgroud)
哪个电话:
_get(type, id) {
return new Promise(async (resolve, reject) => {
var data = _json[id] = _json[id] || await this._api(type, id);
console.log(data)
if(isAsset(data)) {
resolve(data);
} else if(isEntry(data)) {
await this._scan(data);
resolve(data);
} else {
const error = 'Response is not entry/asset.';
console.log(error);
reject(error);
}
});
}
Run Code Online (Sandbox Code Playgroud)
API调用是:
_api(type, id) {
return new Promise((resolve, reject) => {
Request('http://cdn.contentful.com/spaces/' + Constants.Contentful.SPACE + '/' + (!type || type === Constants.Contentful.ENTRY ? 'entries' : 'assets') + '/' + id + '?access_token=' + Constants.Contentful.PRODUCTION_TOKEN, (error, response, data) => {
if(error) {
console.log(error);
reject(error);
} else {
data = JSON.parse(data);
if(data.sys.type === Constants.Contentful.ERROR) {
console.log(data);
reject(data);
} else {
resolve(data);
}
}
});
});
}
Run Code Online (Sandbox Code Playgroud)
返回条目时,会扫描该条目:
_scan(data) {
return new Promise((resolve, reject) => {
if(data && data.fields) {
const keys = Object.keys(data.fields);
keys.forEach(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));
}
if(i === keys.length - 1) {
resolve();
}
});
} else {
const error = 'Required data is unavailable.';
console.log(error);
reject(error);
}
});
}
Run Code Online (Sandbox Code Playgroud)
如果找到链接引用,则会发出其他请求,然后将生成的JSON注入到原始JSON中以代替引用:
_inject(fields, key, index, data) {
if(isNaN(index)) {
fields[key] = data;
} else {
fields[key][index] = data;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,我正在使用async,await而且Promise我相信他们想要的庄园.最终发生的事情:在返回原始请求后,对引用数据的调用(得到_scan的结果)最终发生.这最终会向内容模板提供不完整的数据.
有关我的构建设置的其他信息:
Mic*_*ley 13
我相信这个问题在你的forEach电话中_scan.供参考,请参阅使用ES7驯服异步野兽的这篇文章:
但是,如果您尝试使用异步函数,那么您将得到一个更微妙的错误:
Run Code Online (Sandbox Code Playgroud)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');这将编译,但问题是这将打印出来:
Run Code Online (Sandbox Code Playgroud)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;
}
}
Run Code Online (Sandbox Code Playgroud)
同样,_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;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4731 次 |
| 最近记录: |