This article表示由于forEach
不能识别异步,因此以下代码无法解决。
story.chapterUrls.forEach(function(chapterUrl) {
getJSON(chapterUrl).then(function(chapter) {
addHtmlToPage(chapter.html);
});
})
story.chapterUrls
是一个包含网址的数组,getJSON
从网址中提取数据。但是上面的代码似乎正在工作,尽管每个getJSON()
阻止下一个。 Waht是该代码的问题吗?
答案 0 :(得分:1)
TL; DR最优解决方案位于底部
正如我之前解释的那样,问题是虽然 if #available(iOS 11.0, *) {
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0),
scrollView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 0),
scrollView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: 0),
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0)
])
}else {
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0),
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0),
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0)
])
}
保证了getJSON()
的执行顺序,但每个forEach()
的回调执行顺序都不是 保证,因为它是异步执行的。
解决此问题的两种规范方法是使用.then()
或Promise.all()
:
Array#reduce()
:
Promise.all()
使用Promise.all(story.chapterUrls.map(function(chapterUrl) {
return getJSON(chapterUrl);
})).then(chapters => chapters.forEach(function(chapter) {
addHtmlToPage(chapter.html);
});
,Promise.all()
回调等待所有章节解析,然后同时添加所有HTML。这样做的缺点是使页面空白比下面的方法稍长一些,但总体上会更快完成,因为所有异步请求都是并行发生的。
.then()
:
Array#reduce()
使用story.chapterUrls.reduce(async function(promise, chapterUrl) {
await promise;
const chapter = await getJSON(chapterUrl);
addHtmlToPage(chapter.html);
}, Promise.resolve());
,创建一个承诺链,按顺序异步加载每个章节,在每个章节被提取后立即添加HTML。这样做的好处是可以尽快将内容放在页面上,但总体上需要更长的时间,因为它不会并行获取资源。
使用对上述方法的一个棘手的小改动,您可以并行加载资源和按顺序显示它们,因为它们在{<1}}加载后加载 / em>获取资源:
Array#reduce()
但是,如果您希望一次性渲染所有内容,而不是让页面空白一点,请使用await
方法。