閱讀完您能夠知道什麼:前端
對於異步、在作前端開發、發送請求後咱們並非立馬能過拿到數據、而是和服務器進行一系列操做(域名解析、三次握手、服務器通訊/響應)當服務器給到咱們數據會觸發咱們的異步回調方法、並走咱們的方法邏輯、這個部分稱爲異步!在node中絕大多數的操做都是以異步的方式進行調用、這樣作的好處是咱們能夠很天然的進行並行I/O操做、而無需等待前面的I/O結束、在編程模型上能夠極大的提高效率。node
咱們在啓動一個serve服務的時候、編寫服務事件監聽、而且把監聽的結果用回調函數接收、事件編程具備輕量級、鬆耦合、只關注事物點等優點!可是也有別的問題就是事件與事件之間各自獨立、如何協做是一個問題。git
Node保持了Javascript在瀏覽器中單線程的特色,單線程最大的好處就是不用像多線程編程那樣到處在乎狀態的同步問題、這裏沒有死鎖的存在、也沒有線程上下文交換所帶來的性能開銷!es6
單線程的弱點(三方面)github
在Node中、長時間的CPU佔用也會致使後續的異步I/O發不出調用、已完成的異步I/O的回調函數也不會獲得及時的執行!Node爲了解決這個問題採用了Web Workers相同的思路解決單線程大計算量的問題
child_process
、這樣咱們能夠把大量的計算所有分解出去、而後經過進程間的事件消息來傳遞結果、我在編寫Chrome插件也使用過這種方式去拆分計算邏輯下降運算形成的堵塞。編程
起初Node只能在Linux平臺運行、後面Node使用libuv實現跨平臺操做!json
graph TD Node.js --> libuv libuv --> *nix libuv --> Windows
進行技術選型前、咱們想要了解技術具體適合什麼樣的場景、這樣咱們才能作到在合適的場景使用合適的技術達到一個比較好的效果!關於Node探討較多的是I/O密集型和CPU密集型;後端
Node處理I/O的能力是值得稱讚的、Node面向網絡而且擅長並行I/O、可以有效的組織起更多的硬件資源!I/O密集的最大好處在於Node利用事件循環的處理能力、而不是爲了每個請求而去獨立啓動一個線程、資源佔用極少!api
event loop在處理全部的任務/事件時,都是沿着事件隊列順序執行的,因此在其中任何一個任務/事件自己沒有完成以前,其它的回調、監聽器、超時、nextTick()的函數都得不到運行的機會,由於被阻塞的event loop根本沒機會處理它們,此時程序最好的狀況是變慢,最糟的狀況是停滯不動,像死掉同樣。因此當Node.js遇到高CPU佔用率的任務時,event loop會被阻塞住,有解決方案嗎?答案是有,Node雖然沒有提供多線程用於計算支持、可是仍是有如下兩個方式來充分利用CPU。瀏覽器
Node能夠經過編寫C/C++擴展的方式更高效的利用CPU,將一些V8不能作到的性能極致的地方提供C/C++來實現
若是單線程的Node不能知足需求、甚至用了C/C++擴展後還以爲不夠、那麼能夠選擇經過子進程的方式、將一部分Node進程看成常駐服務進程用於計算、利用進程間的消息來傳遞結果、將計算與I/O分離
隨着Javascript被普遍重視起來後、也暴露出一個問題,先天就缺少的一項功能:模塊、隨着Node的誕生、後面社區也爲其制定了相應的規範
CommonJs規範
、固然在此以前也有不少的模塊化技術、以往也有經過閉包或者一些命名空間還有AMD和RequireJS、今天咱們只講如今服務端Node所使用的模塊CommonJs規範!
每一個文件就是一個模塊,有本身的做用域。在一個文件裏面定義的變量、函數、類,都是私有的,對其餘文件不可見隔離開了、使得用戶徹底沒必要考慮變量被污染。經過
require('xxx/地址') 引入模塊
和經過module.exports.xxx = xxx
導出當前模塊的方法或者變量
//mode.js
function add(a,b){
return a + b;
}
module.exports.add = add; //導出模塊方法
//index.js
const mode = require('./mode.js') //引入模塊
console.log(mode) //{ add: [Function: add]
let sum = mode.add(1,2);
console.log(sum) //3
複製代碼
在模塊中,上下文提供了require()方法來引入外部模塊。對應導出的模塊來講,上下文提供了module對象、而exports是module的一個屬性、而且它是惟一導出的入口、將想要導出的模塊掛載到exports對象就可暴露給外部模塊引入使用!
Node引入模塊須要經歷三個步驟 1:路徑分析 2:文件定位 3:編譯執行
Node中模塊分爲兩類:一類是Node提供的模塊,稱爲
核心模塊
,另一種是用戶編寫的模塊稱之爲文件模塊
,核心模塊
在Node源碼編譯中、就已經編譯成二進制執行文件、在Node進程時、部分核心模塊就已經被直接加載進內存中,文件模塊
則是在運行時動態加載,須要完整的路徑分析、文件定位、編譯執行過程、速度比核心模塊慢。
瀏覽器會緩存靜態腳本文件已提升性能、node對引入過的文件也會作緩存、以減小二次引入時的開銷,不一樣的地方在於、瀏覽器僅僅緩存的文件、而Node緩存的事編譯和執行以後的對象、不論是核心模塊仍是文件模塊都具備緩存、不一樣的地方是核心模塊緩存檢查優先於文件模塊的緩存檢查。還有一種我稱他爲
特殊模塊
也叫自定義模塊、這種模塊一般是第三方包、這類的模塊查找是最費時間的、也是全部模塊中最慢的一種!、他的查找過程有點相似原型鏈、在同層的node_moudles裏找、找不到遞歸自父級、在找不到再往父級的父級、知道找到根節點 /
關於require文件擴展名分析:CommonJs容許你不寫文件後綴、沒有文件後綴的狀況下Node會以 .js .json .node次序補齊擴展名、依次嘗試,因此說若是是.json和.node文件咱們本身給他補齊會快一些、還能夠同步配合緩存、能夠大幅度緩解Node單線程中阻塞式調用的缺陷。
先後端的JavaScript分別擱置在
http的兩端
、他們所扮演的角色各不相同、也正是由於如此前者依賴於帶寬後者依賴CPU和內存資源、Node模塊引入大部分都是同步的、若是前端也採用這種方式會形成體驗感特別很差、鑑於網絡緣由CommonJs發現並不適合前端、因此出現一個AMD規範(異步模塊定義)
AMD文檔地址
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb = function() {
return beta.verb();
//Or:
return require("beta").verb();
}
});
//建立一個名爲"alpha"的模塊,使用了require,exports,和名爲"beta"的模塊:
複製代碼
CMD規範是由國內玉伯提出、專門適用於瀏覽器、異步加載模塊,只有模塊被真正使用是纔去執行加載、CMD規範整合了CommonJS和AMD規範的特色
define(function(require, exports, module){
var module2 = require('./module')
//也能夠引入依賴模塊(異步)
require.async('./module1', function (m3) {
...
})
//暴露模塊
exports.xxx = value
})
複製代碼
ES6模塊化,也是如今用的最多的模塊化技術,在ES6中每個模塊便是一個文件,在文件中定義的變量,函數,對象在外部是沒法獲取的。您須要把它暴露出去才能夠被使用!
import和require的區別
//【es6】
//index.js
import mode from "./mode.js"
console.log(mode(1,2))
//mode.js
function add(a,b){
return a + b
}
export default add;
//或者
//mode.js
export function add(a,b){
return a + b
}
//index
import { add } from "./mode.js"
複製代碼
總結:ES6模塊和CommonJs模塊主要有如下兩大區別
一、CommonJs模塊輸出的是一個值的拷貝,ES6模塊輸出的是值的引用。
二、CommonJs模塊是運行時加載,ES6模塊是編譯時輸出接口。