在學習Node的過程當中,咱們要了解一些基礎概念。什麼是Node他又解決了哪些問題以及Node的特色。包括傻傻分不清的進程和線程,同步與異步,阻塞和非阻塞,以及Node中核心的(Event Loop)事件環的概念。javascript
Node.js是一個基於 Chrome V8 引擎的JavaScript運行環境(runtime),Node不是一門語言是讓js運行在後端的運行時,而且不包括javascript全集,由於在服務端中不包含DOM
和BOM
,Node也提供了一些新的模塊例如http,fs模塊等。Node.js 使用了事件驅動
、非阻塞式 I/O
的模型,使其輕量又高效而且Node.js 的包管理器 npm,是全球最大的開源庫生態系統。事件驅動與非阻塞IO後面咱們會一一介紹。到此咱們已經對node有了簡單的概念。java
Node在處理高併發,I/O密集場景有明顯的性能優點node
Web主要場景就是接收客戶端的請求讀取靜態資源和渲染界面,因此Node很是適合Web應用的開發。ajax
進程是操做系統分配資源和調度任務的基本單位,線程是創建在進程上的一次程序運行單位,一個進程上能夠有多個線程。數據庫
因而可知瀏覽器是多進程的,而且從咱們的角度來看咱們更加關心瀏覽器渲染引擎npm
渲染引擎內部是多線程的,內部包含兩個最爲重要的線程ui線程和js線程。這裏要特別注意ui線程和js線程是互斥的,由於JS運行結果會影響到ui線程的結果。ui更新會被保存在隊列中等到js線程空閒時當即被執行。後端
javascript在最初設計時設計成了單線程,爲何不是多線程呢?若是多個線程同時操做DOM那豈不會很混亂?這裏所謂的單線程指的是主線程是單線程的,因此在Node中主線程依舊是單線程的。咱們來張圖看看單線程和多線程promise
單線程特色是節約了內存,而且不須要在切換執行上下文。並且單線程不須要管鎖的問題,這裏簡單說下鎖的概念。例以下課了你們都要去上廁所,廁所就一個,至關於全部人都要訪問同一個資源。那麼先進去的就要上鎖。而對於node來講。下課了就一我的去廁所,因此免除了鎖的問題!瀏覽器
setTimeout(function(){
console.log(1)
})
setTimeout(function(){
console.log(2)
})
setTimeout(function(){
console.log(3)
})
複製代碼
當設置定時器時,會將定時器對應的回調函數依次的放到隊列中,執行時按照放置的順序依次執行。tomcat
function stack(){
console.log(1);
fn1();
function fn1(){
console.log(2);
fn2();
function fn2(){
console.log(3)
}
}
}
stack();
複製代碼
咱們能夠看到js是在全局的上下文中執行的,調用棧入棧的順序是stack->fn1->fn2,看成用域銷燬時先須要先銷燬fn2->fn1->stack
整個的這種運行機制又稱爲Event Loop(事件循環)
咱們先來張圖看看node是如何工做的
在libuv內部有這樣一個事件環機制。在node啓動時會初始化事件環
┌───────────────────────┐
┌─>│ timers(計時器) │
| | 執行setTimeout以及 |
| | setInterval的回調。 |
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks |
│ | 處理網絡、流、tcp的錯誤 |
| | callback |
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
| | node內部使用 |
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐ ┌───────────────┐
│ │ poll(輪詢) │ │ incoming: │
| | 執行poll中的i/o隊列 | <─────┤ connections, │
| | 檢查定時器是否到時 | │ data, etc. |
│ └──────────┬────────────┘ └───────────────┘
│ ┌──────────┴────────────┐
│ │ check(檢查) │
| | 存放setImmediate回調 |
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks |
│ 關閉的回調例如 |
| sockect.on('close') |
└───────────────────────┘
複製代碼
這裏每個階段都對應一個事件隊列,當event loop執行到某個階段時會將當前階段對應的隊列依次執行。當隊列執行完畢或者執行的數量超過上線時,會轉入下一個階段。這裏咱們重點關注poll階段
兩者很是類似,可是兩者區別取決於他們何時被調用.
setTimeout(function timeout () {
console.log('timeout');
},0);
setImmediate(function immediate () {
console.log('immediate');
});
複製代碼
nextTick並不屬於事件循環的某個階段,他的執行方式是在各個階段切換的中間執行,來段噁心的代碼
setImmediate(function(){
console.log(1);
process.nextTick(function(){
console.log(2);
});
});
process.nextTick(function(){
console.log(3);
setImmediate(function(){
console.log(4);
})
});
// 3 1 4 2
複製代碼
這裏就不解釋了,若是你懂了,說明就明白nextTick的執行時機了!(nextTick不要遞歸調用,不然後面階段的callback將沒法執行)
任務可分爲宏任務和微任務
process.nextTick > promise.then > setTimeout > setImmediate
複製代碼
經過上面的學習咱們知道了任務的執行順序,要注意的是Promise.then方法被定義在了nextTick以後執行
同步異步取決於被調用者,阻塞非阻塞取決於調用者
到此咱們詳細的解說了一下node中的概念,喜歡的點個贊吧^_^! 支持個人能夠給我打賞哈