Node.js包教不包會(huì)|實(shí)驗(yàn)代碼+運(yùn)行結(jié)果

課程來源:https://www.shiyanlou.com/courses/493【@實(shí)驗(yàn)樓】

第1節(jié) 一個(gè)最簡單的 express 應(yīng)用

1.1 新建lesson1,進(jìn)去里面安裝express

1.2 新建app.js

app.js 代碼

1.3 運(yùn)行app.js,打開瀏覽器峭竣,輸入http://localhost:3000/

瀏覽器結(jié)果

第2節(jié) 學(xué)習(xí)使用外部模塊

2.1 新建lesson1,并生成一份它的 package.json惰赋。

package.json

2.2 安裝依賴洛口, express 和 utility 兩個(gè)模塊

package.json添加了依賴信息

2.3 新建app.js

app.js 代碼

2.4 運(yùn)行app.js,在瀏覽器輸入http://localhost:3000/?q=alsotang

瀏覽器結(jié)果

第3節(jié) 使用 superagent 與 cheerio 完成簡單爬蟲

3.1 新建文件夾特咆,進(jìn)去之后 npm init

新建lesson3文件夾并進(jìn)入
新建package.json

3.2 安裝依賴:express,superagent,cheerio

3.3 寫應(yīng)用邏輯

新建app.js
app.js 代碼

3.4 運(yùn)行及結(jié)果

運(yùn)行app.js
瀏覽器運(yùn)行結(jié)果

第4節(jié) 使用 eventproxy 控制并發(fā)

4.1 獲取主頁

4.1.1 新建文件夾,進(jìn)去之后 npm init

4.1.2 安裝依賴:express,superagent,cheerio

4.1.3 寫應(yīng)用邏輯

新建 app.js
app.js 代碼

4.1.4 運(yùn)行及結(jié)果

獲取的鏈接(部分截圖)

4.2 eventproxy介紹

4.2.1 不使用 eventproxy 也不使用計(jì)數(shù)器

// 參考 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);
    });
  });
});

4.2.2 使用計(jì)數(shù)器

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

4.2.3 使用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);
  });

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

  • 先 var ep = new eventproxy(); 得到一個(gè) eventproxy 實(shí)例。
  • 告訴它你要監(jiān)聽哪些事件间唉,并給它一個(gè)回調(diào)函數(shù)绞灼。
    ep.all('event1', 'event2', function (result1, result2) {})。
  • 在適當(dāng)?shù)臅r(shí)候 ep.emit('event_name', eventData)呈野。

4.3 抓取每條url的內(nèi)容

完整代碼如下:

var eventproxy = require('eventproxy');
var superagent = require('superagent');
var cheerio = require('cheerio');
var 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);
      var href = url.resolve(cnodeUrl, $element.attr('href'));
      topicUrls.push(href);
    });

    var ep = new eventproxy();

    ep.after('topic_html', topicUrls.length, function (topics) {
      topics = topics.map(function (topicPair) {
        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]);
        });
    });
  });
運(yùn)行結(jié)果(部分截圖)

第5節(jié) 使用 async 控制并發(fā)

5.1 準(zhǔn)備工作

  • mkdir lesson5 && cd lesson5
  • npm init
  • npm install --save async
  • touch app.js

5.2 app.js 代碼如下

5.3 運(yùn)行及結(jié)果

結(jié)果 部分截圖1
結(jié)果 部分截圖2

第6節(jié) 測試用例:mocha低矮,should,istanbul

6.1 編寫測試用例

6.1.1 準(zhǔn)備工作

6.1.2 編寫測試用例

新建 main.js
main.js 代碼

6.1.3 運(yùn)行及結(jié)果

符合預(yù)期

6.2 執(zhí)行測試

6.2.1 修改main.js被冒,暴露 fibonacci

在末尾加這句

6.2.2 準(zhǔn)備工作

安裝依賴:should
新建test文件夾及test.main.js

6.2.3 main.test.js 代碼

安裝mocha

6.2.4 運(yùn)行及結(jié)果

安裝 mocha
在lesson6目錄下運(yùn)行測試文件
運(yùn)行結(jié)果:測試通過

6.2.4 增加測試军掂,修改main.test.js,并運(yùn)行

main.test.js
運(yùn)行結(jié)果:有3個(gè)沒通過

6.2.5 根據(jù)報(bào)錯(cuò)更新main.js昨悼,使測試全部通過

更新fibonacci
運(yùn)行結(jié)果:全部通過

以上過程為TDD(測試驅(qū)動(dòng)開發(fā)):先把要達(dá)到的目的都描述清楚蝗锥,然后讓現(xiàn)有的程序跑不過 case,再修補(bǔ)程序率触,讓 case 通過终议。

6.3 使用isbantul(代碼覆蓋率)

  • 行覆蓋率(line coverage):是否每一行都執(zhí)行了?
  • 函數(shù)覆蓋率(function coverage):是否每個(gè)函數(shù)都調(diào)用了?
  • 分支覆蓋率(branch coverage):是否每個(gè)if代碼塊都執(zhí)行了穴张?
  • 語句覆蓋率(statement coverage):是否每個(gè)語句都執(zhí)行了细燎?

6.3.1 準(zhǔn)備工作

  • subo npm install --global mocha
  • sudo npm install --save-dev mocha
  • sudo nom i istanbul -g
  • istanbul cover _mocha

6.3.2 運(yùn)行結(jié)果


第7節(jié) 瀏覽器端測試:mocha,chai陆馁,phantomjs

7.1 瀏覽器環(huán)境執(zhí)行

7.1.1 準(zhǔn)備工作

  • mkdir lesson7 && cd lesson7
  • mkdir vendor && cd vendor
  • npm i -g mocha # 安裝全局的 mocha 命令行工具
  • mocha init . # 生成腳手架
測試原型目錄結(jié)構(gòu)

7.1.2 在index.html插入如下代碼

7.1.3 在test.js輸入如下代碼

7.1.4 打開index.html,結(jié)果如下

7.2 命令行環(huán)境執(zhí)行

7.2.1 安裝 mocha-phantomjs

  • sudo npm i -g mocha-phantomjs

7.2.2 index.html增加如下代碼

7.2.3 運(yùn)行

報(bào)錯(cuò)找颓,不知道是什么原因?叮贩?


第8節(jié) 測試用例:supertest

8.1 準(zhǔn)備工作

8.2 編寫app.js

8.3 編寫test/app.test.js

8.4 運(yùn)行及結(jié)果

--

第9節(jié) 正則表達(dá)式

  • i :不區(qū)分大小寫
  • g:匹配多個(gè)
  • m :^ 和 $ 可以匹配每一行的開頭击狮。
  • 加 g 會(huì)返回?cái)?shù)組,不加 g 則返回比較詳細(xì)的信息
  • 加 g 之后益老,如果你的正則不是字面量的正則彪蓬,而是存儲(chǔ)在變量中的話,這個(gè)變量就會(huì)變得有記憶
  • [\s\S],[^]:能匹配包括 \n 在內(nèi)的所有字符

第10節(jié) benchmark 怎么寫(測試性能)

  • mkdir lesson10 && cd lesson10
  • npm init
  • npm install benchmark --save
  • touch main.js

第11節(jié) 作用域與閉包

11.1 var作用域

  • 內(nèi)部函數(shù)可以訪問外部函數(shù)的變量捺萌,外部不能訪問內(nèi)部函數(shù)的變量档冬。
ex1.js
運(yùn)行及結(jié)果

內(nèi)部函數(shù)child可以訪問變量age,而外部函數(shù)parent不可以訪問child中的變量childAge桃纯,因此會(huì)拋出沒有定義變量的異常酷誓。

  • 如果忘記var,那么變量就被聲明為全局變量了态坦。
ex2.js
運(yùn)行及結(jié)果
  • JavaScript 中盐数,變量的局部作用域是函數(shù)級(jí)別的。不同于 C 語言伞梯,在 C 語言中玫氢,作用域是塊級(jí)別的。
ex3.js
運(yùn)行及結(jié)果

11.2 閉包

ex4.js
運(yùn)行及結(jié)果
  • 閉包的一個(gè)坑
ex5.js
運(yùn)行及結(jié)果
  • 上面這個(gè)代碼塊打印五個(gè) 5:setTimeout 中的 i 是對(duì)外層 i 的引用谜诫。當(dāng) setTimeout 的代碼被解釋的時(shí)候漾峡,運(yùn)行時(shí)只是記錄了 i 的引用,而不是值喻旷。而當(dāng) setTimeout 被觸發(fā)時(shí)生逸,五個(gè) setTimeout 中的 i 同時(shí)被取值,由于它們都指向了外層的同一個(gè) i且预,而那個(gè) i 的值在迭代完成時(shí)為 5牺陶,所以打印了五次 5。
  • 下面這個(gè)代碼塊打印0-4:把 i 賦值成一個(gè)局部的變量辣之,從而擺脫外層迭代的影響。

11.3 this

  • 函數(shù)有所屬對(duì)象時(shí):指向所屬對(duì)象
ex6.js
運(yùn)行及結(jié)果
  • 函數(shù)沒有所屬對(duì)象:指向全局對(duì)象
ex7.js
運(yùn)行及結(jié)果
運(yùn)行及結(jié)果(接上)
  • 構(gòu)造器中的 this:指向新對(duì)象
ex8.js
運(yùn)行及結(jié)果
  • apply 和 call 調(diào)用以及 bind 綁定:指向綁定的對(duì)象
ex9.js
運(yùn)行及結(jié)果
運(yùn)行及結(jié)果(接上)

第13節(jié) 持續(xù)集成平臺(tái):travis

13.1 注冊travis賬號(hào)

https://travis-ci.org/

我直接關(guān)聯(lián)了自己的github賬號(hào)

13.2 選擇自己需要測試的倉庫

倉庫主目錄結(jié)構(gòu)
test目錄結(jié)構(gòu)

13.3 寫.travis.yml

13.4 運(yùn)行及結(jié)果

當(dāng) .travis.yml 完成后皱炉,travis自動(dòng)被觸發(fā)

點(diǎn)擊查看結(jié)果
詳細(xì)結(jié)果


第15節(jié) Mongodb 與 Mongoose 的使用

15.1 安裝mongodb

15.2 使用mongodb和mongoose模塊

  • mkdir lesson15 && cd lesson15
  • touch test_db.js
  • npm install mongoose
test_db.js 代碼
  • node test_db.js
添加成功
  • mongod
  • 在另一個(gè)終端輸入 mongo
數(shù)據(jù)庫結(jié)果

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末怀估,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌多搀,老刑警劉巖歧蕉,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異康铭,居然都是意外死亡惯退,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門从藤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來催跪,“玉大人,你說我怎么就攤上這事夷野“谜簦” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵悯搔,是天一觀的道長骑丸。 經(jīng)常有香客問我,道長妒貌,這世上最難降的妖魔是什么通危? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮灌曙,結(jié)果婚禮上菊碟,老公的妹妹穿的比我還像新娘。我一直安慰自己平匈,他們只是感情好框沟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著增炭,像睡著了一般忍燥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上隙姿,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天梅垄,我揣著相機(jī)與錄音,去河邊找鬼输玷。 笑死队丝,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的欲鹏。 我是一名探鬼主播机久,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赔嚎!你這毒婦竟也來了膘盖?” 一聲冷哼從身側(cè)響起胧弛,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎侠畔,沒想到半個(gè)月后结缚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡软棺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年红竭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喘落。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡茵宪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出揖盘,到底是詐尸還是另有隱情眉厨,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布兽狭,位于F島的核電站憾股,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏箕慧。R本人自食惡果不足惜服球,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望颠焦。 院中可真熱鬧斩熊,春花似錦、人聲如沸伐庭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽圾另。三九已至霸株,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間集乔,已是汗流浹背去件。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留扰路,地道東北人尤溜。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像汗唱,于是被迫代替她去往敵國和親宫莱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容