Node.js 5:《使用 async 控制并發(fā)》

2018-08-07 15:22 更新

目標

建立一個 lesson5 項目,在其中編寫代碼。

代碼的入口是 app.js,當調用 node app.js 時,它會輸出 CNode(https://cnodejs.org/ ) 社區(qū)首頁的所有主題的標題,鏈接和第一條評論,以 json 的格式。

注意:與上節(jié)課不同,并發(fā)連接數(shù)需要控制在 5 個。

輸出示例:

[
  {
    "title": "【公告】發(fā)招聘帖的同學留意一下這里",
    "href": "http://cnodejs.org/topic/541ed2d05e28155f24676a12",
    "comment1": "呵呵呵呵"
  },
  {
    "title": "發(fā)布一款 Sublime Text 下的 JavaScript 語法高亮插件",
    "href": "http://cnodejs.org/topic/54207e2efffeb6de3d61f68f",
    "comment1": "沙發(fā)!"
  }
]

知識點

  1. 學習 async(https://github.com/caolan/async ) 的使用。這里有個詳細的 async demo 演示:https://github.com/alsotang/async_demo
  2. 學習使用 async 來控制并發(fā)連接數(shù)。

課程內(nèi)容

lesson4 的代碼其實是不完美的。為什么這么說,是因為在 lesson4 中,我們一次性發(fā)了 40 個并發(fā)請求出去,要知道,除去 CNode 的話,別的網(wǎng)站有可能會因為你發(fā)出的并發(fā)連接數(shù)太多而當你是在惡意請求,把你的 IP 封掉。

我們在寫爬蟲的時候,如果有 1000 個鏈接要去爬,那么不可能同時發(fā)出 1000 個并發(fā)鏈接出去對不對?我們需要控制一下并發(fā)的數(shù)量,比如并發(fā) 10 個就好,然后慢慢抓完這 1000 個鏈接。

用 async 來做這件事很簡單。

這次我們要介紹的是 async 的 mapLimit(arr, limit, iterator, callback) 接口。另外,還有個常用的控制并發(fā)連接數(shù)的接口是 queue(worker, concurrency),大家可以去 https://github.com/caolan/async#queueworker-concurrency 看看說明。

這回我就不帶大家爬網(wǎng)站了,我們來專注知識點:并發(fā)連接數(shù)控制。

對了,還有個問題是,什么時候用 eventproxy,什么時候使用 async 呢?它們不都是用來做異步流程控制的嗎?

我的答案是:

當你需要去多個源(一般是小于 10 個)匯總數(shù)據(jù)的時候,用 eventproxy 方便;當你需要用到隊列,需要控制并發(fā)數(shù),或者你喜歡函數(shù)式編程思維時,使用 async。大部分場景是前者,所以我個人大部分時間是用 eventproxy 的。

正題開始。

首先,我們偽造一個 fetchUrl(url, callback) 函數(shù),這個函數(shù)的作用就是,當你通過

fetchUrl('http://www.baidu.com', function (err, content) {
  // do something with `content`
});

調用它時,它會返回 http://www.baidu.com 的頁面內(nèi)容回來。

當然,我們這里的返回內(nèi)容是假的,返回延時是隨機的。并且在它被調用時,會告訴你它現(xiàn)在一共被多少個地方并發(fā)調用著。

// 并發(fā)連接數(shù)的計數(shù)器
var concurrencyCount = 0;
var fetchUrl = function (url, callback) {
  // delay 的值在 2000 以內(nèi),是個隨機的整數(shù)
  var delay = parseInt((Math.random() * 10000000) % 2000, 10);
  concurrencyCount++;
  console.log('現(xiàn)在的并發(fā)數(shù)是', concurrencyCount, ',正在抓取的是', url, ',耗時' + delay + '毫秒');
  setTimeout(function () {
    concurrencyCount--;
    callback(null, url + ' html content');
  }, delay);
};

我們接著來偽造一組鏈接

var urls = [];
for(var i = 0; i < 30; i++) {
  urls.push('http://datasource_' + i);
}

這組鏈接的長這樣:

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號