中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

使用Nodejs怎么實現模塊化和事件循環

發布時間:2021-06-01 16:31:18 來源:億速云 閱讀:123 作者:Leah 欄目:web開發

這期內容當中小編將會給大家帶來有關使用Nodejs怎么實現模塊化和事件循環,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

1 Node.js簡介

Node.js 到底是什么?開始學習的時候,對于前端的一些知識領域沒有太多的接觸(當然現在也一樣),對于 Node.js 的印象就是,它和Javascript 的語法幾乎一樣,然后是寫后端的。記得當時還竊喜,學了 Javascript = 啥都會了!好了切入正題

以前 Javascript 都是運行在瀏覽器上邊的,Javascript 是一種高級語言,計算機不能直接讀懂,畢竟二進制的計算機的世界里邊就只有010101...,在這個時候瀏覽器中的 JavaScript 引擎,就充當了翻譯官的角色,把 JavaScript 想要做什么手把手翻譯給計算機,這其中的編譯過程就不細說(我暫時也說不清楚)。

Node.js 基于 Chrome 瀏覽器的 V8 引擎,可以高效的編譯 Javascript,所以可以說 Node.js 是除瀏覽器以外的另一個 Javascript 運行環境。

記得在騰訊云的云函數上折騰過微信公眾號的簡單的自動回復,當時對前端代碼的模塊化有了小小的體會,Node.js 的功勞!

2 初體驗

server.js 文件如下

// 引入 http 模塊
var http = require("http");

//  用 http 模塊創建服務
 //req 獲取 url 信息 (request)
 //res 瀏覽器返回響應信息 (response)
http.createServer(function (req, res) {
  // 設置 HTTP 頭部,狀態碼是 200,文件類型是 html,字符集是 utf8
  //Content-Type字段用于定義網絡文件的類型和網頁的編碼,決定瀏覽器將以什么形式、什么編碼讀取這個文件,不寫就可能會出現亂碼哦
  res.writeHead(200, {
    "Content-Type": "text/html;charset=UTF-8"
  });

  // 往頁面打印值
  res.write('小林別鬧');

  // 結束響應
  res.end();

}).listen(3000); // 監聽3000端口

安裝了 Node 的前提下在終端運行 node server.js 打開瀏覽器,在地址欄輸入http://localhost:3000/ 就能看到頁面打印出來:

使用Nodejs怎么實現模塊化和事件循環

此時我們在本地搭建起一個最簡單的服務器,瀏覽器作為客戶端進行訪問

2.1 模塊化

在上邊的代碼中,我們注意到了有 var http = require("http"); 這樣的語句,作用是引入 http 模塊. 在 Node 中,模塊分為兩類:一是 Node 提供的模塊,稱為核心模塊;二是用戶編寫的模塊,稱為文件模塊.http 就是核心模塊之一,例如使用 http 模塊可以創建服務,path 模塊處理文件路徑,url 模塊用于處理與解析 URL.fs模塊用于對系統文件及目錄進行讀寫操作等.

2.1.1CommonJS

提到模塊化,就必須提一嘴 CommonJS,Node.js 就采用了部分 CommonJS 語法,可以理解為 CommonJS 是一種模塊化的標準.在早期為了解決通過script標簽引入js文件代碼產生的依賴順序易出錯,頂層作用域導致的變量污染等問題

在這里可以梳理一下導出 module.exportsexports 的差別

test2.js 如下:

let str = require('./test1');
console.log(str)

當 test1.js如下:

let str1 = '小林別鬧1'
let str2 = '小林別鬧2'

exports.str1 = str1
exports.str2 = str2
console.log(module.exports === exports)

在終端執行 node test2.js 結果如下:

/*輸出
{ str1: '小林別鬧1', str2: '小林別鬧2' }
true
*/

//改變test1.js文件變量暴露的方式
/*
exports.str1 = str1
module.exports = str2
console.log(module.exports === exports)
輸出:
false
小林別鬧2
*/

/*
exports.str1 = str1
module.exports.str2 = str2
console.log(module.exports === exports)
控制臺輸出:
true
{ str1: '小林別鬧1', str2: '小林別鬧2' }
*/

可以進行一下總結:

在 Node 執行一個文件時,會給這個文件內生成一個 exports 對象和一個 module 對象,而這個module 對象又有一個屬性叫做 exports ,exports 是對 module.exports 的引用,它們指向同一塊地址,但是最終導出的是 module.exports,第二次測試 module.exports = str2 改變了地址,所以 str1 沒有導出.

另外注意,使用 exports 導出是導出一個對象

2.1.2 Es Module

Javascript 也是在不斷的發展進步,這不,Es6版本就加入了Es Module模塊

導出:

export const str1 = '小林別鬧1'
export const str2 = '小林別鬧2'
export default {
    fn() {},
    msg: "小林別鬧"
}

導入:

import { st1,str2,obj } from './test.js'

注意 import,直接 node js 文件執行會報錯的,需要 babel 編譯

比較一下的話就是:

CommonJs 可以動態加載語句,代碼發生在運行時

Es Module 是靜態的,不可以動態加載語句,只能聲明在該文件的最頂部,代碼發生在編譯時

2.1.3 第三方模塊

在Node 中除了可以使用自己提供的核心模塊,自定義模塊,還可以使用第三方模塊

這就需要提到 npm ,npm 是 Node 的包管理工具,已經成為了世界上最大的開放源代碼的生態系統,我們可以下載各種包.

當然包管理工具還有yarn,但是我暫時只用過 npm,因為它隨 node 一起按照提供.

2.2  Node 的事件循環

2.2.1 非阻塞I/O

Java、PHP 或者 .NET 等服務端語言,會為每一個客戶端的連接創建一個新的線程。Node 不會為每一個客戶連接創建一個新的線程,而僅僅使用一個線程。

console.log('1')
setTimeout(() => {
  console.log('2')
})
console.log('3')//輸出132

Javascript 的代碼是從上到下一行行執行的,但是這里就不會阻塞,輸出3,再輸出2

2.2.2事件循環

Node 的事件循環真的好久才弄懂一丟丟,看過很多博客,覺得理解 Node 的事件循環機制,結合代碼及其運行結果來分析是最容易理解的。

libuv 庫負責 Node API 的執行。它將不同的任務分配給不同的線程,形成一個 Event Loop(事件循環),以異步的方式將任務的執行結果返回給 V8 引擎。其中 libuv 引擎中的事件循環分為 6 個階段,它們會按照順序反復運行。每當進入某一個階段的時候,都會從對應的回調隊列中取出函數去執行。當隊列為空或者執行的回調函數數量到達系統設定的閾值,就會進入下一階段。

console.log('start')
setTimeout(() => {//定時器1
  console.log('timer1')
  setTimeout(function timeout () {//定時器2
    console.log('timeout');
  },0);
  setImmediate(function immediate () {//定時器3
    console.log('immediate');
  });
  Promise.resolve().then(function() {
    console.log('promise1')
  })
}, 0)
setTimeout(() => {//定時器4
  console.log('timer2')
  Promise.resolve().then(function() {
    console.log('promise2')
  })
}, 0)
Promise.resolve().then(function() {
  console.log('promise3')
})
console.log('end')

可以 Node 上邊運行一下

使用Nodejs怎么實現模塊化和事件循環

timers 階段:這個階段執行timer(setTimeout、setInterval)的回調

I/O callbacks 階段:處理一些上一輪循環中的少數未執行的 I/O 回調

idle, prepare 階段:僅node內部使用

poll 階段:獲取新的I/O事件, 適當的條件下node將阻塞在這里

check 階段:執行 setImmediate() 的回調

close callbacks 階段:執行 socket 的 close 事件回調

理解:首先執行同步任務,所以會輸出start end,poll階段是事件循環的入口,有異步事件就是從這里進入的,同步任務執行完執行先微任務,輸出 promise3,接下來就是 setTimeout了,由 poll階段一步步到 timers 階段,執行定時器1,輸出 timer1,將定時器2和定時器3加入到隊列里邊,一旦執行一個階段里的一個任務就立刻執行微任務隊列,所以再輸出 promise1,然后執行定時器4,如上輸出timer2,promise2,結合事件再循環,到了 check 階段,執行 setImmediate() 的回調,輸出 immediate,再循環進行,到達 timer 階段,輸出 timeout

使用Nodejs怎么實現模塊化和事件循環

2.2.3瀏覽器的事件循環

瀏覽器和 Node 的事件循環是不一樣的

打算用兩張圖和一段代碼來解釋瀏覽器的事件循環機制,

console.log(1)
setTimeout(()=>{console.log(2)},1000)//宏任務1
async function fn(){
    console.log(3)
    setTimeout(()=>{console.log(4)},20)//宏任務2
    //return Promise.reject()返回失敗狀態的,不會輸出6,弄不清楚為啥
    return Promise.resolve()
}
async function run(){
    console.log(5)
    await fn()
    //console.log(6),
}
run()
//需要執行150ms左右
for(let i=0;i<90000000;i++){}
setTimeout(()=>{//宏任務3
    console.log(7)
    new Promise(resolve=>{
        console.log(8)
        resolve()
    }).then(()=>{console.log(9)})
},0)
console.log(10)
// 1 5 3 10 4 7 8 9 2

執行結果如(請忽略我的工具提示):

使用Nodejs怎么實現模塊化和事件循環

我們可以儲備一些前置知識:JavaScript 是單線程的,任務可以分為同步任務和異步任務,像 console.log('1') 就是同步的,定時器 setTimeout,promise 的回調等就是異步的。同步的很好理解,就從上到下一行一行的執行下來,異步的就有點小復雜了,還會分為宏任務和微任務。

瀏覽器的事件循環機制就是:先執行同步任務,同步任務執行完成,就執行任務隊列里面的任務,那任務隊列里面的任務是哪來的呢?異步任務準備好了就會放進任務隊列,你可以理解為,在任務隊列里邊宏任務和微任務都存在這一個隊列結構管著它們。先后的話,同步任務執行完成后,任務隊列里有微任務,則將微任務執行完,再執行一個宏任務,執行了宏任務可能又產生了微任務,這是就需要再執行完微任務任務。你可以將同步任務看成宏任務,這樣就可以理解為,每執行完一個宏任務都要清理一遍微任務。

使用Nodejs怎么實現模塊化和事件循環

使用Nodejs怎么實現模塊化和事件循環

上邊代碼解釋如下:執行到第一行代碼,輸出 1,執行到第二行代碼 setTimeout 屬于宏任務1,準備1000毫秒后加入任務隊列,然后執行函數 run,輸出 5,因為 await 的存在,我們需要等待 fn函數執行完畢,這里是通過 await 關鍵字將異步函數變成同步的,執行 fn 時輸出 3,又出現一個 setTimeout 宏任務2,準備時間20毫秒,返回成功狀態的Promise,輸出 6,for 循環需要150ms,這是宏任務2,準備完畢,進入任務隊列,繼續向下,有一個 setTimeout 宏任務3,無需準備加入任務隊列,執行最后一行代碼,輸出 10,至此同步任務全部執行完畢,接下來是異步任務了,任務隊列是隊列的數據結構,遵循先進先出的原則,此時任務隊列中有宏任務2和宏任務3,先執行宏任務2,輸出 4,再執行宏任務3,輸出 7promise本身是同步的,輸出 8,回調then 里邊的代碼是微任務,宏任務3執行后,發現有微任務存在,清理一邊微任務,輸出 9,整個流程經過1000毫秒后,宏任務1加入任務隊列,輸出 2

上述就是小編為大家分享的使用Nodejs怎么實現模塊化和事件循環了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

惠安县| 梓潼县| 祥云县| 九台市| 孟连| 吴桥县| 武乡县| 沁源县| 吉林市| 买车| 稷山县| 娱乐| 大埔县| 南召县| 冀州市| 崇文区| 宣威市| 淮南市| 和静县| 茶陵县| 庄河市| 北海市| 根河市| 陕西省| 本溪市| 甘孜县| 西青区| 泗洪县| 巴南区| 元谋县| 淮南市| 诸城市| 昌都县| 禄丰县| 南宫市| 河北区| 苏尼特右旗| 根河市| 余姚市| 偏关县| 沙河市|