最稳的pk10计划iphone 北京pk10计划手机软件 北京pk10数字的规律 超神手机版pk10软件 pk10北京赛车9码技巧 pk10四期倍投计划表 pk10极速赛车论坛 北京赛车冠军怎样选5码 北京赛车系统下载安装 pk10教程视频 北京pk10选号公式 北京赛车pk10赚钱技巧 北京赛车怎么提升概率 pk10技巧北京快三 北京pk10大小计划
VB.net 2010 視頻教程 VB.net 2010 視頻教程 VB.net 2010 視頻教程
SQL Server 2008 視頻教程 c#入門經典教程 Visual Basic從門到精通視頻教程
當前位置:
首頁 > 網站開發 > JavaScript >
  • JavaScript教程之Node.js官方文檔:到底什么是阻塞

  • 2019-06-16 18:06 來源:未知

譯者按: Node.js文檔閱讀系列之一。

  • 原文: Overview of Blocking vs Non-Blocking
  • 譯者: Fundebug

為了保證可讀性,本文采用意譯而非直譯。

這篇博客將介紹Node.js的阻塞(Blocking)與非阻塞(Non-Blocking)。我會提到Event Loop與libuv,但是不了解它們也不會影響閱讀。讀者只需要有一定的JavaScript基礎,理解Node.js的回調函數(callback pattern)就可以了。

博客中提到了很多次I/O,它主要指的是使用libuv與系統的磁盤與網絡進行交互。

阻塞(Blocking)

阻塞指的是一部分Node.js代碼需要等到一些非Node.js代碼執行完成之后才能繼續執行。這是因為當阻塞發生時,Event Loop無法繼續執行。

對于Node.js來說,由于CPU密集的操作導致代碼性能很差時,不能稱為阻塞。當需要等待非Node.js代碼執行時,才能稱為阻塞。Node.js中依賴于libuv的同步方法(以Sync結尾)導致阻塞,是最常見的情況。當然,一些不依賴于libuv的原生Node.js方法有些也能導致阻塞。

Node.js中所有與I/O相關的方法都提供了異步版本,它們是非阻塞的,可以指定回調函數,例如fs.readFile。其中一些方法也有對應的阻塞版本,它們的函數名以Sync結尾,例如fs.readFileSync。

代碼示例

阻塞的方法是同步執行的,而非阻塞的方法是異步執行。

以讀文件為例,下面是同步執行的代碼:

const fs = require('fs');
const data = fs.readFileSync('/file.md'); // 文件讀取完成之前,代碼會阻塞,不會執行后面的代碼
console.log("Hello, Fundebug!"); // 文件讀取完成之后才會打印

對應的異步代碼如下:

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
}); // 代碼不會因為讀文件阻塞,會繼續執行后面的代碼
console.log("Hello, Fundebug!"); // 文件讀完之前就會打印

第一個示例代碼看起來要簡單很多,但是它的缺點是會阻塞代碼執行,后面的代碼需要等到整個文件讀取完成之后才能繼續執行。

在同步代碼中,如果讀取文件出錯了,則錯誤需要使用try...catch處理,否則進程會崩潰。對于異步代碼,是否處理回調函數的錯誤則取決于開發者。

我們可以將示例代碼稍微修改一下,下面是同步代碼:

const fs = require('fs');
const data = fs.readFileSync('/file.md'); 
console.log(data);
moreWork(); // console.log之后再執行

異步代碼如下:

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
  console.log(data);
});
moreWork(); // 先于console.log執行

在第一個示例中,console.log將會先于moreWork()執行。在第二個示例中,由于fs.readFile()是非阻塞的,代碼可以繼續執行,因此moreWork()會先于console.log執行。

moreWork()不用等待讀取整個文件,可以繼續執行,這是Node.js可以增加吞吐量的關鍵。

并發與吞吐量

Node.js中JS代碼執行是單線程的,因此并發指的是Event Loop可以在執行其他代碼之后再去執行回調函數。如果希望代碼可以并發執行,則所有非JavaScript代碼比如I/O執行時,必須保證Event Loop繼續運行。

舉個例子,假設Web服務器的每個請求需要50ms完成,其中45ms是數據庫的I/O操作。如果使用非阻塞的異步方式執行數據庫I/O的話,則可以節省45ms來處理其他請求,這可以極大地提高系統的吞吐量。

Event Loop這種方式與其他許多語言都不一樣,通常它們會創建新的線程來處理并發。

混用阻塞與非阻塞代碼會出問題

當我們處理I/O時,應該避免以下代碼:

const fs = require('fs');
fs.readFile('/file.md', (err, data) => {
  if (err) throw err;
  console.log(data);
});
fs.unlinkSync('/file.md');

上面的示例中,fs.unlinkSync()很可能在fs.readFile()之前執行,也就是說,我們在讀取file.md之前,這個文件就已經被刪掉了。

為了避免這種情況,我們應該是要非阻塞方式,來保證它們按照正確的順序執行。

const fs = require('fs');
fs.readFile('/file.md', (readFileErr, data) => {
  if (readFileErr) throw readFileErr;
  console.log(data);
  fs.unlink('/file.md', (unlinkErr) => {
    if (unlinkErr) throw unlinkErr;
  });
});

上面的示例中,我們把非阻塞的fs.unlink()放在fs.readFile()的回調函數中。

參考

  • libuv
  • About Node.js

關于Fundebug

Fundebug專注于JavaScript、微信小程序、微信小游戲、支付寶小程序、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了10億+錯誤事件,付費客戶有Google、360、金山軟件、百姓網等眾多品牌企業。歡迎大家免費試用!

pk10赛车冠军技巧
最稳的pk10计划iphone 北京pk10计划手机软件 北京pk10数字的规律 超神手机版pk10软件 pk10北京赛车9码技巧 pk10四期倍投计划表 pk10极速赛车论坛 北京赛车冠军怎样选5码 北京赛车系统下载安装 pk10教程视频 北京pk10选号公式 北京赛车pk10赚钱技巧 北京赛车怎么提升概率 pk10技巧北京快三 北京pk10大小计划
好用的麻将app 开金店靠什么赚钱 什么手工艺品最赚钱 幸运五分彩怎么玩稳赚 梦幻西游摆摊卖胚子赚钱吗 以太坊交易合法吗 赚钱扑鱼游戏 闲来广东麻将app下载 今年免费的赚钱好项目有哪些