亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

Nodejs實戰心得之eventproxy模塊控制并發

2019-11-20 11:23:55
字體:
來源:轉載
供稿:網友

目標

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

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

輸出示例:

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

挑戰

以上文目標為基礎,輸出 comment1 的作者,以及他在 cnode 社區的積分值。

示例:

[ {  "title": "【公告】發招聘帖的同學留意一下這里",  "href": "http://cnodejs.org/topic/541ed2d05e28155f24676a12",  "comment1": "呵呵呵呵",  "author1": "auser",  "score1": 80 }, ...]

知識點

體會 Node.js 的 callback hell 之美

學習使用 eventproxy 這一利器控制并發

課程內容

這一章我們來到了 Node.js 最牛逼的地方――異步并發的內容了。

上一課我們介紹了如何使用 superagent 和 cheerio 來取主頁內容,那只需要發起一次 http get 請求就能辦到。但這次,我們需要取出每個主題的第一條評論,這就要求我們對每個主題的鏈接發起請求,并用 cheerio 去取出其中的第一條評論。

CNode 目前每一頁有 40 個主題,于是我們就需要發起 1 + 40 個請求,來達到我們這一課的目標。

后者的 40 個請求,我們并發地發起:),而且不會遇到多線程啊鎖什么的,Node.js 的并發模型跟多線程不同,拋卻那些觀念。更具體一點的話,比如異步到底為何異步,Node.js 為何單線程卻能并發這類走近科學的問題,我就不打算講了。對于這方面有興趣的同學,強烈推薦 @樸靈 的 《九淺一深Node.js》: http://book.douban.com/subject/25768396/ 。

有些逼格比較高的朋友可能聽說過 promise 和 generator 這類概念。不過我呢,只會講 callback,主要原因是我個人只喜歡 callback。

這次課程我們需要用到三個庫:superagent cheerio eventproxy(https://github.com/JacksonTian/eventproxy )
手腳架的工作各位自己來,我們一步一步來一起寫出這個程序。

首先 app.js 應該長這樣

var eventproxy = require('eventproxy');var superagent = require('superagent');var cheerio = require('cheerio');// url 模塊是 Node.js 標準庫里面的// http://nodejs.org/api/url.htmlvar url = require('url');var cnodeUrl = 'https://cnodejs.org/';superagent.get(cnodeUrl) .end(function (err, res) {  if (err) {   return console.error(err);  }  var topicUrls = [];  var $ = cheerio.load(res.text);  // 獲取首頁所有的鏈接  $('#topic_list .topic_title').each(function (idx, element) {   var $element = $(element);   // $element.attr('href') 本來的樣子是 /topic/542acd7d5d28233425538b04   // 我們用 url.resolve 來自動推斷出完整 url,變成   // https://cnodejs.org/topic/542acd7d5d28233425538b04 的形式   // 具體請看 http://nodejs.org/api/url.html#url_url_resolve_from_to 的示例   var href = url.resolve(cnodeUrl, $element.attr('href'));   topicUrls.push(href);  });  console.log(topicUrls); });

運行 node app.js

輸出如下圖:

OK,這時候我們已經得到所有 url 的地址了,接下來,我們把這些地址都抓取一遍,就完成了,Node.js 就是這么簡單。
抓取之前,還是得介紹一下 eventproxy 這個庫。

用 js 寫過異步的同學應該都知道,如果你要并發異步獲取兩三個地址的數據,并且要在獲取到數據之后,對這些數據一起進行利用的話,常規的寫法是自己維護一個計數器。

先定義一個 var count = 0,然后每次抓取成功以后,就 count++。如果你是要抓取三個源的數據,由于你根本不知道這些異步操作到底誰先完成,那么每次當抓取成功的時候,就判斷一下 count === 3。當值為真時,使用另一個函數繼續完成操作。
而 eventproxy 就起到了這個計數器的作用,它來幫你管理到底這些異步操作是否完成,完成之后,它會自動調用你提供的處理函數,并將抓取到的數據當參數傳過來。
假設我們不使用 eventproxy 也不使用計數器時,抓取三個源的寫法是這樣的:

// 參考 jquery 的 $.get 的方法

$.get("http://data1_source", function (data1) { // something $.get("http://data2_source", function (data2) {  // something  $.get("http://data3_source", function (data3) {   // something   var html = fuck(data1, data2, data3);   render(html);  }); });});

上述的代碼大家都寫過吧。先獲取 data1,獲取完成之后獲取 data2,然后再獲取 data3,然后 fuck 它們,進行輸出。

但大家應該也想到了,其實這三個源的數據,是可以并行去獲取的,data2 的獲取并不依賴 data1 的完成,data3 同理也不依賴 data2。

于是我們用計數器來寫,會寫成這樣:

(function () { var count = 0; var result = {}; $.get('http://data1_source', function (data) {  result.data1 = data;  count++;  handle();  }); $.get('http://data2_source', function (data) {  result.data2 = data;  count++;  handle();  }); $.get('http://data3_source', function (data) {  result.data3 = data;  count++;  handle();  }); function handle() {  if (count === 3) {   var html = fuck(result.data1, result.data2, result.data3);   render(html);  } }})();

丑的一逼,也不算丑,主要我寫代碼好看。

如果我們用 eventproxy,寫出來是這樣的:

var ep = new eventproxy();ep.all('data1_event', 'data2_event', 'data3_event', function (data1, data2, data3) { var html = fuck(data1, data2, data3); render(html);});$.get('http://data1_source', function (data) { ep.emit('data1_event', data); });$.get('http://data2_source', function (data) { ep.emit('data2_event', data); });$.get('http://data3_source', function (data) { ep.emit('data3_event', data); });

好看多了是吧,也就是個高等計數器嘛。

ep.all('data1_event', 'data2_event', 'data3_event', function (data1, data2, data3) {});

這一句,監聽了三個事件,分別是 data1_event, data2_event, data3_event,每次當一個源的數據抓取完成時,就通過 ep.emit() 來告訴 ep 自己,某某事件已經完成了。

當三個事件未同時完成時,ep.emit() 調用之后不會做任何事;當三個事件都完成的時候,就會調用末尾的那個回調函數,來對它們進行統一處理。

eventproxy 提供了不少其他場景所需的 API,但最最常用的用法就是以上的這種,即:

先 var ep = new eventproxy(); 得到一個 eventproxy 實例。

告訴它你要監聽哪些事件,并給它一個回調函數。ep.all('event1', 'event2', function (result1, result2) {})。
在適當的時候 ep.emit('event_name', eventData)。

eventproxy 這套處理異步并發的思路,我一直覺得就像是匯編里面的 goto 語句一樣,程序邏輯在代碼中隨處跳躍。本來代碼已經執行到 100 行了,突然 80 行的那個回調函數又開始工作了。如果你異步邏輯復雜點的話,80 行的這個函數完成之后,又激活了 60 行的另外一個函數。并發和嵌套的問題雖然解決了,但老祖宗們消滅了幾十年的 goto 語句又回來了。

至于這套思想糟糕不糟糕,我個人倒是覺得還是不糟糕,用熟了看起來蠻清晰的。不過 js 這門渣渣語言本來就亂嘛,什么變量提升(http://www.cnblogs.com/damonlan/archive/2012/07/01/2553425.html )啊,沒有 main 函數啊,變量作用域啊,數據類型常常簡單得只有數字、字符串、哈希、數組啊,這一系列的問題,都不是事兒。
編程語言美丑啥的,咱心中有佛就好。

回到正題,之前我們已經得到了一個長度為 40 的 topicUrls 數組,里面包含了每條主題的鏈接。那么意味著,我們接下來要發出 40 個并發請求。我們需要用到 eventproxy 的 #after API。

大家自行學習一下這個 API 吧:https://github.com/JacksonTian/eventproxy#%E9%87%8D%E5%A4%8D%E5%BC%82%E6%AD%A5%E5%8D%8F%E4%BD%9C
我代碼就直接貼了哈。

// 得到 topicUrls 之后// 得到一個 eventproxy 的實例var ep = new eventproxy();// 命令 ep 重復監聽 topicUrls.length 次(在這里也就是 40 次) `topic_html` 事件再行動ep.after('topic_html', topicUrls.length, function (topics) { // topics 是個數組,包含了 40 次 ep.emit('topic_html', pair) 中的那 40 個 pair // 開始行動 topics = topics.map(function (topicPair) {  // 接下來都是 jquery 的用法了  var topicUrl = topicPair[0];  var topicHtml = topicPair[1];  var $ = cheerio.load(topicHtml);  return ({   title: $('.topic_full_title').text().trim(),   href: topicUrl,   comment1: $('.reply_content').eq(0).text().trim(),  }); }); console.log('final:'); console.log(topics);});topicUrls.forEach(function (topicUrl) { superagent.get(topicUrl)  .end(function (err, res) {   console.log('fetch ' + topicUrl + ' successful');   ep.emit('topic_html', [topicUrl, res.text]);  });});

輸出長這樣:

完整的代碼請查看 lesson4 目錄下的 app.js 文件

總結

今天介紹的 eventproxy 模塊是控制并發用的,有時我們需要同時發送 N 個 http 請求,然后利用得到的數據進行后期的處理工作,如何方便地判斷數據已經全部并發獲取得到,就可以用到該模塊了。而模塊不僅可以在服務端使用,也可以應用在客戶端

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久av在线看| 久99久在线视频| 久久久精品一区二区| 亚洲aⅴ日韩av电影在线观看| 欧美日韩免费看| 日韩av手机在线观看| 亚洲精品99久久久久| 久久久久久久久电影| 国产精品视频色| 国语自产精品视频在线看一大j8| 韩国精品久久久999| 91av福利视频| 国产视频观看一区| 韩国三级日本三级少妇99| 国产精品一区二区久久久| 91精品久久久久久久久久入口| 97人人模人人爽人人喊中文字| 国产深夜精品福利| 中文字幕欧美日韩va免费视频| 精品国产老师黑色丝袜高跟鞋| 欧美高清第一页| 久久精品国产清自在天天线| 国产69精品99久久久久久宅男| 亚洲欧美精品中文字幕在线| 国产精品欧美激情| 国产精品视频区| 亚洲天堂网站在线观看视频| 国产成人精品视频在线观看| 成人免费激情视频| 成人性生交大片免费看小说| 成人黄色片网站| 91在线观看欧美日韩| 亚洲欧洲在线播放| 国产成人综合精品在线| 日韩中文字幕国产精品| 91中文字幕一区| 欧美福利视频网站| 亚洲日韩中文字幕| 国产成人鲁鲁免费视频a| 国产偷国产偷亚洲清高网站| 欧美成人亚洲成人| 国产精品久久久久久久久久久久久| 国产视频一区在线| 91精品国产高清久久久久久91| 欧美精品生活片| 国产精品久久不能| 亚洲在线视频福利| 色偷偷噜噜噜亚洲男人| 国内精久久久久久久久久人| 中文字幕亚洲精品| 欧美精品中文字幕一区| 日韩最新在线视频| 久久综合久久八八| 国产精品揄拍500视频| 精品高清一区二区三区| 精品国内亚洲在观看18黄| 欧美大片免费观看在线观看网站推荐| 在线免费看av不卡| 亚洲精品自拍视频| 色悠悠久久88| 国产精品一区久久久| 亚洲国产高清福利视频| 亚洲第一页在线| 欧美成人四级hd版| 亚洲已满18点击进入在线看片| 国产精品白嫩初高中害羞小美女| 久久免费成人精品视频| 久久伊人免费视频| 亚洲国内高清视频| 欧美精品在线观看| 亚洲精品动漫久久久久| 中文字幕一区日韩电影| 91亚洲va在线va天堂va国| 亚洲国产精品小视频| 色综合色综合网色综合| 日韩国产激情在线| 亚洲激情在线观看| 国产综合福利在线| 国产一区二区三区三区在线观看| 国产91在线视频| 亚洲电影av在线| 国产精品久久久久久久av大片| 亚洲欧洲在线看| 色哟哟入口国产精品| 国产精品天天狠天天看| 欧美一级免费看| 日本一区二区在线免费播放| 日韩中文有码在线视频| 久热爱精品视频线路一| 最近2019中文字幕mv免费看| 日韩成人激情在线| 亚洲成人久久电影| 欧美视频精品一区| 久久成人人人人精品欧| 国产精品免费视频久久久| 91九色蝌蚪国产| 尤物yw午夜国产精品视频| 国产不卡视频在线| 亚洲乱码国产乱码精品精| 日韩av手机在线看| 69av在线视频| 国产精品视频久久久久| 亚洲v日韩v综合v精品v| 欧美国产亚洲精品久久久8v| 国产精品色婷婷视频| 亚洲欧美国产日韩天堂区| 久久国产精品网站| 欧美又大粗又爽又黄大片视频| 亚洲女人天堂网| 中文字幕日本精品| 2023亚洲男人天堂| 奇米四色中文综合久久| 国产亚洲视频中文字幕视频| 欧美精品在线免费观看| 国产精品老牛影院在线观看| 久久最新资源网| 亚洲r级在线观看| 亚洲欧美日韩国产中文| 国产精品爱久久久久久久| 国产精品视频区| 欧美丝袜第一区| 91免费的视频在线播放| 亚洲美女中文字幕| 成人午夜在线影院| 91久久在线视频| 亚洲天堂av在线播放| 亚洲国产精品小视频| 精品欧美aⅴ在线网站| 亚洲精品动漫久久久久| 亚洲欧美在线一区二区| 91亚洲午夜在线| 亚洲片在线资源| 国产免费一区二区三区香蕉精| 欧美国产日韩一区二区| 国产成人一区二区| 美女黄色丝袜一区| 亚洲一区久久久| 97精品一区二区视频在线观看| 日韩欧美国产黄色| 一区二区三区四区视频| 日韩欧美成人网| 51ⅴ精品国产91久久久久久| 国产精品成人一区二区三区吃奶| 另类色图亚洲色图| 日韩精品高清视频| 久久婷婷国产麻豆91天堂| 91精品视频一区| 久久99国产精品久久久久久久久| 国产精品va在线播放我和闺蜜| 欧美多人爱爱视频网站| 正在播放国产一区| 久久久av网站| 欧美视频在线免费看| 国产精品免费观看在线| 久久久久久香蕉网| 欧美极品美女视频网站在线观看免费| 91精品视频免费| 亚洲一级片在线看| 中文字幕亚洲综合久久| 亚洲第一页自拍| 91av中文字幕| 日韩美女写真福利在线观看| 国产精品成人观看视频国产奇米| 奇门遁甲1982国语版免费观看高清|