Node.js學習筆記

1.1. Part 0 :Node.js簡介

1.1.1. a)Node.js簡介

Node.js不是一門語言也不是框架,他只是基於Google V8引擎的JavaScript運行時環境,同時結合Libuv擴展了JavaScript功能,使之支持io、fs等只有語言纔有的特性,使得JavaScript可以同時具備DOM操做(瀏覽器)I/O文件讀寫操做數據庫(服務器端)等能力,是目前最簡單的全棧式語言前端

Node.js一般被用來開發低延遲的網絡應用,也就是那些須要在服務器端環境和前端實時收集交換數據的應用(API、即時聊天、微服務)。node

1.1.2. b)什麼是Node.js?

  • Node.js不是JavaScript應用,不是語言(JavaScript是語言),不是想Rails(Ruby)或Django(Python)同樣的框架,也不是想Nginx同樣的Web服務器。Node.js是JavaScript運行時環境
  • 構建在Chrome's V8這個著名的JavaScript引擎之上,Chrome V8引擎以C/C++ 爲主,至關於使用JavaScript寫法,轉成C/C++ 調用,大大的下降了學習成本
  • 事件驅動(event-driven),非阻塞 I/O 模型,簡單點講就是每一個函數都是異步的,最後由Libuv這個C/C++編寫的事件循環處理庫來處理這些 I/O操做,隱藏了非阻塞 I/O 的具體細節,簡化併發變成模型,讓你能夠輕鬆的編寫共性能的Web應用,因此他是輕量且高效的
  • 使用 npm 做爲包管理器,目前 npm 是開源庫裏包管理最大的生態,功能強大,截止到2017年12月,模塊數量超過60W+

總結:Node.js是構建在JavaScript之上的,事件觸發和異步的,專爲數據密集型實時程序設計的。其目標是讓併發編程更簡單,,主要應用在以網絡編程爲主的 I/O 密集型應用。他是開源的,跨平臺,而且高效(尤爲是 I/O 處理)react

1.1.3. c)基本原理

下面是一張 Node.js 早期的架構圖,來自 Node.js 之父 Ryan Dahl 的演講稿,在今天依然不過期,它簡要的介紹了 Node.js 是基於 Chrome V8引擎構建的,由事件循環(Event Loop)分發 I/O 任務,最終工做線程(Work Thread)將任務丟到線程池(Thread Pool)裏去執行,而事件循環只要等待執行結果就能夠了。git

核心概念github

  • Chrome V8是 Google 發佈的開源JavaScript 引擎,採用C/C++ 編寫,在Google的 Chrome瀏覽器中被使用。Chrome V8 引擎能夠獨立運行,也能夠用來嵌入到C/C++ 應用程序中執行。
  • Event Loop事件循環(由Libuv提供)
  • Thread Pool線程池(由Libuv提供)

梳理一下數據庫

  • Chrome V8 是 JavaScript 引擎
  • Node.js 內置 Chrome V8 引擎,因此它使用的 JavaScript 語法
  • JavaScript 語言的一大特色就是單線程,也就是說,同一個時間只能作一件事
  • 單線程就意味着,全部任務須要排隊,前一個任務結束,纔會執行後一個任務。若是前一個任務耗時很長,後一個任務就不得不一直等着。
  • 若是排隊是由於計算量大,CPU 忙不過來,倒也算了,可是不少時候 CPU 是閒着的,由於 I/O 很慢,不得不等着結果出來,再往下執行
  • CPU 徹底能夠無論 I/O 設備,掛起處於等待中的任務,先運行排在後面的任務
  • 將等待中的 I/O 任務放到 Event Loop 裏
  • 由 Event Loop 將 I/O 任務放到線程池裏
  • 只要有資源,就盡力執行

 

核心express

  • Chrome V8 解釋並執行 JavaScript 代碼(這就是爲何瀏覽器能執行 JavaScript 緣由)
  • libuv 由事件循環和線程池組成,負責全部 I/O 任務的分發與執行

在解決併發問題上,異步是最好的解決方案,能夠拿排隊和叫號機來理解npm

  • 排隊:在排隊的時候,你除了等以外什麼都幹不了
  • 叫號機:你要作的是先取號碼,等輪到你的時候,系統會通知你,這中間,你能夠作任何你想作的事兒

1.3.5. Node.js應用場景

Node.js簡稱 數據密集型實時程序(DIRT)。由於Node.js自身在I/O 上很是輕量,它善於將數據從一個管道混排或代理到另外一個官道上,這能在處理大量請求時持有不少開放的鏈接,而且只佔用一小部份內存。它的設計目標是保證影響能力,跟瀏覽器同樣。編程

Node.js使用場景主要分爲4大類:react-native

  • 1)跨平臺:覆蓋你能想到的面向用戶的全部平臺,傳統的PC Web端,以及PC客戶端 nw.js/electron 、移動端 cordova、HTML五、react-nativeweex,硬件 ruff.io 等
  • 2)Web應用開發:網站、Api、RPC服務等
  • 3)前端:三大框架 React \ Vue \ Angular 輔助開發,以及工程化演進過程(使用Gulp/Webpack 構建 Web 開發工具)
  • 4)工具:npm上各類工具模塊,包括各類前端預編譯、構建工具 Grunt / Gulp、腳手架,命令行工具,各類奇技淫巧等

1.3.6. Node核心:異步流程控制

 Node.js是爲異步而生的,他把複雜的事情都給作了(高併發,低延時),交給用戶的只是有點難用的Callback寫法。

直面問題纔能有更好的解決方式,Node.js的異步是整個學習Node.js過程當中的重中之重。

  • 1)異步流程控制學習重點
  • 2)Api 寫法:Error-first Callback和EventEmitter
  • 3)中流砥柱:Promise
  • 4)終極解決方案:Async/Await

1.3.6.2. 2)Api寫法:Error-first Callback 和 EventEmitter

a)Error-first Callback 定義錯誤優先的回調寫法只須要注意2條規則便可:

  • 回調函數的第一個參數返回的error對象,若是error發生了,它會做爲第一個err參數返回,若是沒有,通常作法是返回null。
  • 回調函數的第二個參數返回的是任何成功響應的結果數據。若是結果正常,沒有error發生,err會被設置爲null,並在第二個參數就出返回成功結果數據。

b)EventEmitter

事件模塊是 Node.js 內置的對觀察者模式「發佈/訂閱」(publish/subscribe)的實現,經過EventEmitter屬性,提供了一個構造函數。該構造函數的實例具備 on 方法,能夠用來監聽指定事件,並觸發回調函數。任意對象均可以發佈指定事件,被 EventEmitter 實例的 on 方法監聽到。

 Node.js的API都是異步的,同步的函數是奢求,要查API文檔,在高併發場景下慎用。

1.3.6.3. 3)中流砥柱:Promise

回調地獄

Node.js 由於採用了錯誤優先的回調風格寫法,致使sdk裏導出都是回調函數。若是組合調用的話,就會特別痛苦,常常會出現回調裏嵌套回調的問題,你們都很是厭煩這種寫法,稱之爲Callback Hell,即回調地獄。一個經典的例子來自著名的Promise模塊q文檔裏。

step1(function (value1) {
    step2(value1, function(value2) {
        step3(value2, function(value3) {
            step4(value3, function(value4) {
                // Do something with value4
            });
        });
    });
});

Promise意味着[許願|承諾]一個尚未完成的操做,但在將來會完成的。與Promise最主要的交互方法是經過將函數傳入它的then方法從而獲取得Promise最終的值或Promise最終最拒絕(reject)的緣由。要點有三個:

  • 遞歸,每一個異步操做返回的都是promise對象
  • 狀態機:三種狀態轉換,只在promise對象內部能夠控制,外部不能改變狀態
  • 全局異常處理

 1)定義

var promise = new Promise(function(resolve, reject) {
  // do a thing, possibly async, then…

  if (/* everything turned out fine */) {
    resolve("Stuff worked!");
  }
  else {
    reject(Error("It broke"));
  }
});

每一個Promise定義都是同樣的,在構造函數裏傳入一個匿名函數,參數是 resolve 和 reject,分別表明成功和失敗時候的處理。

2)調用

promise.then(function(text){
    console.log(text)// Stuff worked!
    return Promise.reject(new Error('我是故意的'))
}).catch(function(err){
    console.log(err)
})

它的主要交互方式是經過then函數,若是Promise成功執行resolve了,那麼它就會將resolve的值傳給最近的then函數,做爲它的then函數的參數。若是出錯reject,那就交給catch來捕獲異常就行了。

Promise 的最大優點是標準化,各種異步工具庫都按照統一規範實現,即便是async幻術也能夠無縫集成。因此用 Promise 封裝API通用性強,用起來簡單,學習成本低。在async幻術普及以前,絕大部分應用都是採用 Promise來作異步流程控制的,因此掌握 Promise是Node.js學習必需要會的。

1.3.6.4. 4)終極解決方案:Async/Await

Async/Await是異步操做的終極解決方案,Koa 2在node 7.6發佈以後,立馬發佈了正式版本,而且推薦使用async函數來編寫Koa中間件。

這裏給出一段Koa 2應用裏的一段代碼

exports.list = async (ctx, next) => {
  try {
    let students = await Student.getAllAsync();

    await ctx.render('students/index', {
      students : students
    })
  } catch (err) {
    return ctx.api_error(err);
  }
};

它作了3件事兒

  • 經過await Student.getAllAsync();來獲取全部的students信息。
  • 經過await ctx.render渲染頁面
  • 因爲是同步代碼,使用try/catch作的異常處理

4.1 正常寫法

const pkgConf = require('pkg-conf');

async function main(){
    const config = await pkgConf('unicorn');

    console.log(config.rainbow);
    //=> true
}
main();

變態寫法

const pkgConf = require('pkg-conf');

(async () => {
    const config = await pkgConf('unicorn');

    console.log(config.rainbow);
    //=> true
})();

4.2 await + Promise

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require("fs"));

async function main(){
    const contents = await fs.readFileAsync("myfile.js", "utf8")
    console.log(contents);
}
main();

4.3 await + co + generator

const co = require('co');
const Promise = require('bluebird');
const fs = Promise.promisifyAll(require("fs"));

async function main(){
   const contents = co(function* () {
      var result = yield fs.readFileAsync("myfile.js", "utf8")
      return result;
   })
    console.log(contents);
}
main();

由上面3中基本用法能夠推出Async函數要點以下:

  • Async函數語義上很是好
  • Async不須要執行器,它自己具有執行能力,不像Generator須要co模塊
  • Async函數的異常處理採用try/catch和Promise的錯誤處理,很是強大
  • Await接Promise,Promise自身就足夠應對全部流程了,包括async函數沒有純並行處理機制,也能夠採用Promise裏的all和race來補齊
  • Await釋放Promise的組合能力,外加co和Promise的then,幾乎沒有不支持的場景

 

小結

這部分共講了4個小點,都是極其直接的必須掌握的知識點。

  • 1) 異步流程控制學習重點
  • 2)Api寫法:Error-first Callback 和 EventEmitter
  • 3)中流砥柱:Promise
  • 4)終極解決方案:Async/Await


 這裏有一個練手的項目,感興趣的同窗能夠自行Download,相信會有所收穫https://github.com/oceanMin/cms

相關文章
相關標籤/搜索