認識Node.js/全域執行環境/事件循環、堆疊、佇列和併發模式

X13QQ
X13QQ
Published in
7 min readDec 15, 2020

什麼是Node.js ?

Node.js是許多新創公司選擇的開發語言,跟它的開發生態有關

因為JavaScript在網頁開發上幾乎很難短時間被取代

作為㇐個後端開發它又有豐富的套件生態,甚至前端套件也可以運用在後端,所以只要了解套件 使用,就可以快速開發

Node.js 特性

  • 得益於V8引擎,效能卓著
  • 採用異步(非阻塞) I/O ,不會有因為同步(阻塞) I/O導致效能急遽下降的問題
  • JavaScript 固有的事件驅動、閉包等語言特性,使用起來非常方便
  • Node.js 可跨平台在 Windows、Linux 及 Mac OS X 系統運行

補充

  • 垃圾回收機制(GC)

Node.js會主動做垃圾回收

開發者仍須注意記憶體洩漏

例如無窮迴圈或是閉包的使用失當

  • 閉包(Closure)
function getCount(i) {
var count = i;
var calculate = function(){
console.log(count);
count++;
};
return calculate;
}
var displayCount = getCount(0);
displayCount();
displayCount();
displayCount();
// 0
// 1
// 2

因為變數count還有被另㇐個內部函式引用

所以變數count的生命週期會在每次getCount被呼叫而延⾧,不會被回收

  • 非同步非堵塞IO
var readFile = function (cb) {
setTimeout(function () {
cb('file content:hello async function');
}, 5000);
}
console.log('dosomethingAAA');readFile(function (file) {
console.log(file);
})
console.log('dosomethingBBB');// dosomethingAAA
// dosomethingBBB
// file content:hello async function

Synchronous (同步) , Asynchronous (非同步)

Node.js相當多API都有提供 callback function 以避免阻塞

非同步處理是Node.js㇐大特色

  • Promise Async/Await
var threeSecLater = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('3 sec later');
resolve();
}, 3000);
});
}
var fourSecLater = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('4 sec later');
resolve();
}, 4000);
});
}
;(async() => {
await threeSecLater();
await fourSecLater();
})();
// 3 sec later
// 4 sec later
// 共7秒

讓函式 return Promise 物件

藉由 async/await 的語法,讓非同步 function 變成同步執行

什麼是全域執行環境 ?

「全域」指可在區域裡、JavaScript 檔案裡、詞彙環境裡被取用

全域執行環境創造的兩個東西

  1. 全域物件(Global Object),window
  2. 特殊變數 this

全域物件(Global Object)

「程式碼或者變數不再函式裡就是全域的」

console.log(this);
// Window {0: global, window: Window, self: Window, document: document, name: “”, location: Location, …}

特殊變數(this)

this是JavaScript程式在執行時的綁定(runtime binding),與函式在何處宣告無關,而是取決於函式被呼叫的方式以及地點

var x = 10;
var obj = {
x: 20,
fn: function() {
var test = function() {
console.log(this.x);
};
test();
};
};
obj.fn();
// 10
  1. 脫離物件的 this 基本上沒有任何意義
  2. 沒有意義的 this 會根據嚴格模式以及環境給一個預設值
  3. 嚴格模式底下預設就是 undefined,非嚴格模式在瀏覽器底下預設值是 window
  4. 可以用 call、apply 與 bind 改變 this 的值
  5. 要看 this,就看這個函式「怎麽」被呼叫
  6. 可以把 a.b.c.hello() 看成 a.b.c.hello.call(a.b.c),以此類推,就能輕鬆找出 this 的值

理解 JavaScript 中的事件循環、堆疊、佇列和併發模式
(Learn event loop, stack, queue, and concurrency mode of JavaScript in depth)

  • 堆疊(stack)
function multiply(a, b) {
return a * b
}
function square(n) {
return multiply(n, n)
}
function printSquare(n) {
let squared = square(n)
console.log(squared)
}
printSquare(4)
  • 無窮迴圈
function foo () {
return foo()
}
foo()
  • 阻塞(blocking)
// pseudo code
var foo = $.getSync('//foo.com')
var bar = $.getSync('//bar.com')
var qux = $.getSync('//qux.com')

console.log(foo)
console.log(bar)
console.log(qux)

阻塞的情形導致瀏覽器停滯

  • 非同步處理與堆疊(Async Callback & Call Stack)
console.log('hi')

setTimeout(function () {
console.log('there')
}, 5000)

console.log('JSConfEU')
  • 並行和事件循環 ( Concurrency and Event Loop )

程式執行時,依序將函式放入呼叫堆疊(Call Stack)

如呼叫到Web APIs相關函式則將其回呼函式放入回呼佇列(Callback Queue)等待叫用。

回呼時機來臨時,才將回呼函式放入呼叫堆疊(Call Stack)執行

setTimeout 是JS引擎提供的函式,可預約若干時間後,執行特定函式

setTimeout 非常重要,JavaScript在 ES6 提供的 Promise 的底層就是有使用到 setTimeout

setTimeout 0 ?

參考文章 :
並行模型和事件循環
理解 JavaScript 中的事件循環、堆疊、佇列和併發模式

--

--