Node.js 一二三

Node.js — 3m安裝法

各個平臺都有相關的包管理工具,Ubuntu下的apt-getCentOS下的yum,macOS下的homebrew,便於安裝和卸載軟件。Node.js是名副其實的版本帝,版本更新之快使得上述的工具不適用,開發機器有可能須要同時存在幾個Node.js的大版本,每一個Node.js內置的npm又有版本的差別,並且,國內網絡訪問npmjs.org鏡像速度很慢,因此,推薦適用3m安裝法。前端

  • nvm (node version manager): 解決多版本共存、切換。
  • npm (node package manager): 用於解決Node.js模塊安裝,自己它也是Node.js模塊,每次安裝都會內置某個版本的npm
  • nrm (node registry manager): 解決npm 鏡像訪問慢的問題,提供測速,切換下載源功能

nvm

nvm是一個開源的Node.js版本管理器,經過簡單的bash腳原本管理、切換多個Node.js版本。node

注意:nvm不支持windows版本,但有替代品nvm-windowsreact

安裝:jquery

# nvm 安裝
    curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.0/install.sh | bash
    
    # node.js 安裝 官網最新LTS
    nvm install 12.13.1
複製代碼

查看環境配置:webpack

cat ~/.bash_profile
複製代碼

執行source命令,是環境生效git

source ~/.bash_profile 
複製代碼

注意:也可根據當前終端shell類型查看不一樣配置。若是是zsh,查看.zshrc,若是是bash,查看.bashrcangularjs

查看可安裝版本:github

nvm ls-remote
複製代碼

本機已安裝版本:web

nvm ls
複製代碼

版本類型:shell

  • LTS版本指的是長期支持版本(Long-term Support),有官方支持,推薦給絕大多數用戶使用,通常在生成環境上
  • Current版本指的是當前正在開發的版本,它一般較新,功能點有變更,但沒有徹底穩定,在通過一段時間以後,當前版本可能會變爲LTS版本,通常用於學習

tip: 通常奇數版本都是嘗試性的,通常LTS版本都是偶數

使用 nvm 安裝 Node.js 8.x

nvm install 8
複製代碼

指定默認版本:

nvm alias default 11
複製代碼

切換版本:

nvm use 12
複製代碼

npm

npm 一般稱爲node包管理器。它的主要功能就是管理Node.js的包,包括:安裝、卸載、更新、查看、搜索、發佈等。它最開始的初衷是隻是Node.js包管理器,隨着前端技術react、webpack、browserify等發展,目前npm的定位是廣義的包管理器,包括js、react、mobile、angularjs、browsers、jquery、cordova、bower、gulp、grunt、browserify、docpad、nodebots、tessel等,是開源世界裏最大、生態最健全的包管理器。

Node.js集成了npm,因此安裝Node.js時也一併安裝了。也可使用npm命令來更新安裝。

[sudo] npm install npm -g 
   #指定版本
   [sudo]npm install -g npm@2.9
複製代碼

使用場景有:

  • 從npm鏡像服務器下載第三方模塊
  • 從npm鏡像服務器下載並安裝命令程序到本地
  • 本身發佈模塊到npm鏡像服務器供他人使用

使用npm 安裝模塊:略

nrm

Node.js和其餘語言同樣,默認將模塊託管在 npmjs.org,這是官方的registry(源),registry是指從哪一個源下載Node.js模塊,固然其餘組織或我的也是能夠自建npm registry(源)的,這些非官方的鏡像會按期的和npm官方registry(源)進行同步,通常在10分鐘左右一次。

npm提供的配置源:

npm config set registry <registry url>
複製代碼

這個處理的問題在於切換源的時候比較麻煩。nrm 就是專門用於解決這個問題,它能夠幫助你簡單、快速的在不一樣的npm registry(源)之間進行切換,它默認內置了不少經常使用的源,包括npm、cnpm、taobao、 nj、rednpm、npmMirror,固然你能夠本身經過nrm add維護本身的源。

安裝 nrm

npm install -g nrm
複製代碼

測速:

➜  ~ nrm test

  npm ---- 732ms
  yarn --- 745ms
* cnpm --- 180ms
  taobao - 226ms
  nj ----- Fetch Error
  npmMirror  4493ms
  edunpm - Fetch Error
複製代碼

查看源:

➜  ~ nrm ls

  npm -------- https://registry.npmjs.org/
  yarn ------- https://registry.yarnpkg.com/
* cnpm ------- http://r.cnpmjs.org/
  taobao ----- https://registry.npm.taobao.org/
  nj --------- https://registry.nodejitsu.com/
  npmMirror -- https://skimdb.npmjs.com/registry/
  edunpm ----- http://registry.enpmjs.org/
複製代碼

切換源: 不須要記住 registry 的具體URL,使用registry的名字

nrm use <registry name>
    
    ➜  ~ nrm use taobao

   Registry has been set to: https://registry.npm.taobao.org/
複製代碼

增長源:

nrm add <regsitry url>
複製代碼

目的:

  • 內網安裝速度快,
  • 私有模塊,僅供企業內部使用,安全

異步調用和流程控制

Node.js異步原理

瀏覽器中的異步核心技術是Ajax,異步Javascript和XML。Node.js的異步原理的核心是EventLoop。

看圖說話:

Ajax 異步處理:

Node.js 異步處理:

調用Node.js API的方法的時候,它會把具體操做和回調函數交給 EventLoop 去執行,EventLoop 維護了一個任務隊列(microTask),等異步操做執行完成,隊列中的回調函數會按照先進先出(FIFO)的順序執行。

🌰 獲取目錄下的全部文件的API

  • 異步寫法
# hello-async.js
    
    const fs = require('fs')
    const path = '.'
    fs.readdir(path, function(err, files) {
      if (err) {
        console.log(err)
        return;
      }
      console.log(files)
    })
複製代碼
  • 同步寫法
# hello-sync.js
    
    const fs = require('fs')
    console.log(fs.readdirSync('.'))
複製代碼

注意:高併發場景下慎用同步寫法,否則可能會成爲性能瓶頸,跟Node.js的設計初衷是相悖的。

Node.js自帶的異步寫法

Node.js 中有兩種事件處理方式,callbackEventEmittercallback 採用錯誤優先的回調方式,後者是事件驅動力裏的事件發射器。

錯誤優先的回調方式

Node.js 極其依賴異步代碼和回調來保證執行效率。Node.js SDK 中的 callback 使用 錯誤優先回調(error-first-callback)寫法。規則以下:

  • 回調函數的第一個參數返回的是error對象,若是發生錯誤,該對象會做爲第一個參數返回,正常返回null。
  • 回調函數的第二個參數返回的是全部成功響應的結果數據。

🌰見 hello-err-first.js

這個🌰告訴咱們:

  • 異步流程控制中,異常處理很重要!
  • 只有同步代碼塊才能使用 try-catch
EventEmitter

簡單理解爲「發佈/訂閱」模式,和前端的事件機制相似,如Vue裏面的 $emit$on

const EventEmitter = require('events')
    const obsever = new EventEmitter()
    
    obsever.on('topic', function() {
      console.log('topic has occured')
    })
    
    function main() {
      console.log('start')
      obsever.emit('topic')
      console.log('end')
    }
    
    main()    
複製代碼

**注意:對於EventEmitter 的 on 來講,Node.js容許同一個事件最多指定10個回調函數,超過會發出警告。能夠經過設置setMaxListeners 方法改變。 **

更好的異步流程控制

回調地獄

Node.js採用了錯誤優先的回調寫法,致使SDK中導出的都是回調函數,若是組合調用這些函數,常常會出現回調裏嵌套回調的問題。這種寫法稱之爲回調地獄。

🌰

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

Node.js如何解決回調地獄:

  • async.js 早期的解決方案之一
  • Thunk
  • Promise
  • 生成器Generators/ yield
  • Async/ await

Promise

🌰 1

const fs = require('fs')
function hello(file) {
  return new Promise(function(resolve, reject ) {
    fs.readFile(file, function(err, data) {
      if (err) {
        reject(err)
      } else {
        resolve(data.toString())
      }
    })
  })
}

hello('./hello-events.js')
  .then(function(res) {
    console.log(res)
  })
  .catch(function(err) {
    console.log(err)
  })
複製代碼

使用Promise 實例處理異步流程控制,約定了每一個函數的返回值都是 Promise 對象,所以均可以使用 then 方法處理。

使用rejectresolve 重塑流程:

  • 簡單模式 🌰
const fs = require('fs')
    function hello(file) {
      return new Promise(function(resolve, reject ) {
        fs.readFile(file, function(err, data) {
          if (err) {
            reject(err)
          } else {
            resolve(data.toString())
          }
        })
      })
    }
    
    hello('../main.js')
      .then (function(data) {
          return new Promise(function(resolve, reject) {
            console.log('promise1\n', data)
            resolve(data)
          })
        })
      .then(function(data) {
        return new Promise(function(resolve, reject) {
          console.log('promise2\n', data)
          resolve(1)
        })
      })
      .then(function(data) {
        return new Promise(function(resolve, reject) {
          console.log('promise3\n', data)
          reject(new Error('reject'))
        })
      })
      .catch(function(err) {
        console.log('catch\n', err)
      })


複製代碼
  • 嵌套模式 🌰
const fs = require('fs')
    function hello(file) {
      return new Promise(function(resolve, reject ) {
        fs.readFile(file, function(err, data) {
          if (err) {
            reject(err)
          } else {
            resolve(data.toString())
          }
        })
      })
    }
    
    hello('./main.js')
      .then (function(data) {
        return new Promise(function(resolve, reject) {
          console.log('promise1\n', data)
          resolve(data)
        })
        .then(function(res) {
          return new Promise(function(resolve, reject) {
            console.log('promise2\n', data)
            resolve(1)
          })
        })
        .catch(function(err) {
          console.log('catch', err)
        })
      })
      .catch(function(err) {
        console.log('catch\n', err)
      })
    

複製代碼
  • 鏈式寫法
const fs = require('fs')
    function hello(file) {
      return new Promise(function(resolve, reject ) {
        fs.readFile(file, function(err, data) {
          if (err) {
            reject(err)
          } else {
            resolve(data.toString())
          }
        })
      })
    }
    
    const step1 = function(data) {
      return new Promise(function(resolve, reject) {
        console.log('promise1\n', data)
        resolve(data)
      })
      .then(function(res) {
        return new Promise(function(resolve, reject) {
          console.log('promise2\n', data)
          resolve(1)
        })
      })
      .catch(function(err) {
        console.log('catch', err)
      })
    }
    
    const step2 = function(data) {
      return new Promise(function(resolve, reject) {
        console.log('promise3\n', data)
        reject(new Error('reject'))
      })
    }
    
    hello('./hello-sync.js')
      .then(step1)
      .then(step2)
      .catch(function(err) {
        console.log(err)
      })
    
    

複製代碼
  • 最終版:每一個操做放到獨立文件裏變成模塊
# hello-reflow-module.js
    const hello = require('./tasks/hello')
    const step1 = require('./tasks/step1')
    const step2 = require('./tasks/step2')
    
    hello('../hello-json.json')
      .then(step1)
      .then(step2)
      .catch(function(err) {
        console.log(err)
      })
複製代碼

Tips

一、Node.js各版本對ES6特性支持

二、查看離線文檔: dash

參考資料

書籍:《狼書(卷1):更了不得的Node.js》

社區:cnodejs

相關文章
相關標籤/搜索