我正在开发一个使用两个嵌套异步函数的chrome扩展。但是我希望这些函数是同步的,但是没有一个参数使它同步,API只有async选项。如果可能的话,我需要这两个函数具有嵌套的同步函数行为。告诉我你是否有意义。以下是代码的主要部分:
// Track the number of callbacks from chrome.history.getVisits()
// that we expect to get. When it reaches zero, we have all results.
chrome.history.search({
'text': '', // Return every history item....
'startTime': oneWeekAgo, // that was accessed less than one week ago.
'maxResults': 999999999
},
function (historyItems) {
// For each history item, get details on all visits.;
for (var i = 0; i < historyItems.length; ++i) {
Edited - 0 - I need some code here too.
chrome.history.getVisits({url: historyItems[i].url}, function (visitItems) {
//1 - I want this to happen first, but it happens after 2
for (var j = 0; j < visitItems.length; ++j) {
//Do something that depends on the first function
}
})
//2 -i want this to happen second and after 1, but it happens first, since chrome.history.getvisits is async.
}
//3- I want this to happen third, when the two loops are complete.
})
答案 0 :(得分:2)
JavaScript本质上是单线程的,并且&#34;异步&#34;意味着&#34;在事件队列后面的某个地方&#34;,真的。
因此,在异步任务结束之前无法等待:您必须结束运行才能启动下一个异步任务。唯一的方法是添加要在异步任务结束时调用的代码,称为异步(或回调)链接。
但是,幸运的是,有一些框架可以帮助您以更有条理的方式构建这些东西。其中一个框架是Promises。我将让您访问该链接以获取基本介绍。
首先,让我们&#34;宣传&#34;所需的API调用。第一个:
function historyLastWeek() {
return new Promise(function(resolve, reject) {
chrome.history.search({
'text': '',
'startTime': oneWeekAgo, // don't forget that part
'maxResults': 999999999
}, function(historyItems) {
if(chrome.runtime.lastError) {
reject(chrome.runtime.lastError.message);
} else {
resolve(historyItems);
}
});
});
}
上面的代码返回一个Promise,它将运行chrome.history.search
API调用,并使用历史记录项 resolve ,或者拒绝并返回错误消息。
承诺的一点是,你可以使用.then()
来链接电话。
让我们也宣传chrome.history.getVisits
(注意,它需要一个历史项目,因为我们想要):
function getVisits(historyItem) {
return new Promise(function(resolve, reject) {
chrome.history.getVisits({url: historyItem.url}, function(visitItems) {
if(chrome.runtime.lastError) {
reject(chrome.runtime.lastError.message);
} else {
resolve({
historyItem: historyItem, // let's keep track of it
visitItems: visitItems
});
}
});
});
}
因此,我们有2个承诺返回一系列结果。如何tie them together?
首先,我假设你不打破内循环(所以我运行&#34; getVisits&#34;在&#34; parallel&#34;)。我们Promise.all
就是这样。我们来看看..
historyLastWeek().then(function(historyItems) {
return Promise.all(
// map() returns the array of results of applying a function
// to all members of the array
historyItems.map(getVisits)
);
}).then(function(results) {
// results is an array of objects
results.each(function(result) {
// here, result.historyItem is the history item,
// and result.visitItems is an array of visit items
/* here goes your code #1 */
result.visitItems.each(function(visitItem) {
/* here goes your "Do something that depends on the first function" code */
});
/* here goes your code #2 */
});
/* here goes your code #3 */
}).catch(function(errorMsg) {
// oh noes
});
如果您需要在代码#3之后执行某些操作,那么您还需要宣传最后一个功能,并添加另一个.then()
。
此代码具有不幸的属性:由于JavaScript不是懒惰的,all()
将在执行任何代码之前在单个单片二维数组中收集所有结果,并且您不能早点打断内循环。
您可以将其修改为execute sequentially,而不是收集数组然后进行处理。
historyLastWeek().then(function(historyItems) {
return historyItems.reduce(function(sequence, historyItem) {
return sequence.then(function() {
return getVisits(historyItem);
).then(function(result) {
// here, result.historyItem is the history item,
// and result.visitItems is an array of visit items
/* here goes your code #1 */
result.visitItems.each(function(visitItem) {
/* here goes your "Do something that depends on the first function" code */
});
/* here goes your code #2 */
// Gotta return some promise
return Promise.resolve();
});
}, Promise.resolve());
}).then(function() {
/* here goes your code #3 */
}).catch(function(errorMsg) {
// oh noes
});
请参阅上面的链接,了解所有相关方法的解释。
如果它比非Promise代码更容易或更清晰,那么它是值得商榷的,但至少它可以替代手动链接回调。
答案 1 :(得分:1)
如果你想在32之前支持版本的Chrome,那么你可以做的就是将代码2
和3
移到内部回调中:
function (historyItems) {
var lastItemIndex = historyItems.length - 1;
for (var i = 0; i <= lastItemIndex; ++i) {
chrome.history.getVisits({url: historyItems[i].url}, function(visitItems) {
// 1
for (var j = 0; j < visitItems.length; ++j) {
//Do something that depends on the first function
}
// 2
......................
if (i == lastItemIndex) {
// 3
......................
}
})
}
})