2012-08-16 55 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