2012-08-16 60 views
1

在我的Chrome扩展中,我有一组URL,我想找到第一个未访问的URL。因为chrome.history API是异步的,我的第一本能会做一些奇形怪状的递归迭代中,像这样的......Wrangling异步chrome.history调用

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?或者,有没有完全不同的选择?

回答

1

如果订单很重要,而且您的清单很长,并且较晚找到未访问链接的可能性很高,那么最好的方法就是基本上做您正在做的事情。这是来自流行的async库的forEachSeries实现。

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(); }); 
+0

因此,这将检查(可能长)列表中的每个URL。你什么时候找到哪一个是_first_?你想如何,直到检查之前的所有内容都被检查过,以便你知道它确实是第一个? – Chuck 2012-10-23 03:43:47

+0

列表多长时间?你首先考虑什么?首先根据您的原始URL列表? – Bill 2012-10-23 03:45:36

+0

是的 - 原始问题说我想查找列表中的第一个未访问的URL。同样,它表示担心递归方法会导致堆栈溢出(因此,一个大列表) – Chuck 2012-10-23 03:47:14