在我的Chrome扩展程序中,我有一系列网址,我想找到第一个未访问的网址。因为chrome.history
API是异步的,我的第一直觉就是做一些奇怪的递归迭代,就像这样......
urls = [...];
function recur(idx) {
chrome.history.getVisits(urls[idx], function(visitItems) {
if(visitItems && visitItems.length > 0) {
// Success!
} else {
recur(idx + 1);
}
}
}
recur(0);
但是,这很糟糕(它真的很难看,它可能很慢,并且它会因长列表而中断)。
有没有办法更好地将所有这些调用与chrome.history纠缠在一起?或者,有一个完全不同的选择吗?
答案 0 :(得分:1)
如果订单很重要而且您的清单很长并且很快找到未访问链接的可能性很高,那么最好的办法就是做你正在做的事情。以下是来自热门forEachSeries
库的async
实现。
async.forEachSeries = function (arr, iterator, callback) {
callback = callback || function () {};
if (!arr.length) {
return callback();
}
var completed = 0;
var iterate = function () {
iterator(arr[completed], function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed === arr.length) {
callback(null);
}
else {
iterate();
}
}
});
};
iterate();
};
您将看到您已开始实施的相同递归模式。另一个选择是并行地将它们全部关闭并在它们返回时跟踪它们。一旦列表中的第一项以未访问的方式返回,您就可以退出。注意:以下代码未经测试......
var urls = [a,b,c,d],
unvisitedUrls = [],
count = urls.length,
done = false;
var checkUrl = function(d) {
var url = d;
return function(visitItems) {
if (done) return;
count--;
if (visitItems && visitItems.length > 0) {
unvisitedUrls.push(url);
}
else {
urls.splice(urls.indexOf(url)); // remove the visited url
}
if(unvisitedUrls.indexOf(urls[0]) > -1 || count === 0) {
done = true;
// done checking urls, urls[0] is the winner
}
}
}
urls.forEach(function(d) { chrome.history.getVisits(d, checkUrl(d)); });
如果您的列表长达数百万个项目,那么您可以批量迭代它们而不是一次性完成所有项目。以下是使用https://github.com/caolan/async上的async
库的示例。
var checkUrl = function(url, cb) {
chrome.history.getVisits(url, function(itemVisits) {
if (done) return cb();
count--;
if (visitItems && visitItems.length > 0) {
unvisitedUrls.push(url);
}
else {
urls.splice(urls.indexOf(url)); // remove the visited url
}
if(unvisitedUrls.indexOf(urls[0]) > -1 || count === 0) {
done = true;
// done checking urls, urls[0] is the winner
}
cb();
}
};
async.forEachLimit(urls, 50, checkUrl, function(err) { doSomethingWithWinner(); });