Node.js中的Buffer和事件循環(huán)實例分析

這篇“Node.js中的Buffer和事件循環(huán)實例分析”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Node.js中的Buffer和事件循環(huán)實例分析”文章吧。

創(chuàng)新互聯(lián)是一家專業(yè)的成都網(wǎng)站建設(shè)公司,我們專注網(wǎng)站設(shè)計、網(wǎng)站建設(shè)、網(wǎng)絡(luò)營銷、企業(yè)網(wǎng)站建設(shè),賣友情鏈接,廣告投放為企業(yè)客戶提供一站式建站解決方案,能帶給客戶新的互聯(lián)網(wǎng)理念。從網(wǎng)站結(jié)構(gòu)的規(guī)劃UI設(shè)計到用戶體驗提高,創(chuàng)新互聯(lián)力求做到盡善盡美。

Node.js中的Buffer和事件循環(huán)實例分析

Buffer 的使用


數(shù)據(jù)的二進(jìn)制

  • 計算機中所有的內(nèi)容:文字、數(shù)字、圖片、音頻、視頻最終都會使用二進(jìn)制來表示

  • JS可以直接去處理非常直觀的數(shù)據(jù):比如字符串,我們通常展示給用戶的也是這些內(nèi)容

  • 但你可能會以為JS也能夠處理圖片

    • 事實上在網(wǎng)頁端,圖片一直是交給瀏覽器來處理的

    • JS或者HTML,只是負(fù)責(zé)告訴瀏覽器圖片的地址

    • 瀏覽器負(fù)責(zé)發(fā)送請求獲取這個圖片,并且最終將這個圖片給渲染出來

  • 但是對于服務(wù)端來說是不一樣的

    • 服務(wù)端要處理的本地文件類型相對較多

    • 比如某一個保存文本的文件并不是使用utf-8進(jìn)行編碼的,而是用GBK,那么我們必須讀取到他們的二進(jìn)制數(shù)據(jù),再通過GKB轉(zhuǎn)換成對應(yīng)的文字

    • 比如我們需要讀取的是一張圖片數(shù)據(jù)(二進(jìn)制),再通過某些手段對圖片數(shù)據(jù)進(jìn)行二次的處理(裁剪、格式轉(zhuǎn)換、旋轉(zhuǎn)、添加濾鏡),Node中有一個名為sharp的庫,就是負(fù)責(zé)讀取圖片或者傳入圖片的Buffer對其再進(jìn)行處理的

    • 比如在Node中通過TCP建立長連接,TCP傳輸?shù)氖亲止?jié)流,我們需要將數(shù)據(jù)轉(zhuǎn)成字節(jié)再進(jìn)行傳入,并且需要知道傳輸字節(jié)的大?。蛻舳诵枰鶕?jù)大小來判斷讀取多少內(nèi)容)

Buffer和二進(jìn)制

  • 我們會發(fā)現(xiàn),對于前端開發(fā)來說,通常很少會和二進(jìn)制打交道,但是對于服務(wù)器端來說,為了實現(xiàn)很多功能,我們必須直接去操作其二進(jìn)制的數(shù)據(jù)

  • 所以Node為了可以方便開發(fā)者完成更多功能,提供給了我們一個名為Buffer的類,并且他是全局的

  • 我們前面說過,Buffer中存儲的是二進(jìn)制數(shù)據(jù),那么到底是如何存儲的呢?

    • 我們可以將Buffer看成是一個存儲二進(jìn)制的數(shù)組

    • 這個數(shù)組中的每一項,可以保存8位二進(jìn)制:00000000,剛好是一個字節(jié)

  • 為什么是8位呢?

    • 在計算機中,很少的情況我們會直接操作一位二進(jìn)制,因為一位二進(jìn)制存儲的數(shù)據(jù)是非常有限的

    • 所以通常會將8位合在一起作為一個單元,這個單元稱之為一個字節(jié)(byte

    • 也就是說 1 byte = 8 bit,1kb = 1024 byte,1M = 1024kb, 1 G = 1024 M

    • 比如很多編程語言中的int類型是4個字節(jié),long類型是8個字節(jié)

    • 比如TCP傳輸?shù)氖亲止?jié)流,在寫入和讀取時都需要說明字節(jié)的個數(shù)

    • 比如RGB的值分別都是255,所以本質(zhì)上在計算機中都是用一個字節(jié)存儲的

Buffer和字符串

  • Buffer相當(dāng)于是一個字節(jié)的數(shù)組,數(shù)組中的每一項對于一個字節(jié)的大小

  • 如果我們希望將一個字符串放入到Buffer中,是怎么樣的過程呢?

    • 將字符串直接傳入Buffer類中,然后再創(chuàng)建buffer實例

    • 英文字符串有個特點,每一個字符對應(yīng)一個字節(jié)的二進(jìn)制編碼

const message = 'Hello'
// 使用new關(guān)鍵字創(chuàng)建buffer實例,但這種創(chuàng)建方法已經(jīng)過期了
const buffer = new Buffer(message)
console.log(buffer); // <Buffer 48 65 6c 6c 6f>
console.log(buffer.toString()); // Hello

中文字符串的編解碼

  • buffer的默認(rèn)編碼是utf-8,所以在下列代碼中,Buffer類是使用了utf-8編碼對我們的字符串進(jìn)行編碼,使用的也是utf-8對我們的字符串進(jìn)行解碼

  • 中文字符串有個特點,在utf-8編碼中,一個文字對應(yīng)3個字節(jié)的二進(jìn)制編碼

const message = '你好啊'
// 使用Buffer.from對我們的字符串進(jìn)行解碼
const buffer = Buffer.from(message)
console.log(buffer); // <Buffer e4 bd a0 e5 a5 bd e5 95 8a>
// buffer實例中有個toString方法可以對編碼進(jìn)行解碼
console.log(buffer.toString()); // '你好啊'
  • 那如果編碼和解碼用的是不同形式的編碼結(jié)果會怎么樣呢?

    • 毫無疑問,解碼出來的東西并不是我們原先編碼的字符串

const message = '你好啊'
const buffer = Buffer.from(message, 'utf16le')
console.log(buffer); // <Buffer 60 4f 7d 59 4a 55>
console.log(buffer.toString()); // `O}YJU

Buffer的其他創(chuàng)建方式

創(chuàng)建buffer的方式有很多,我們這里可以通過alloc的方式創(chuàng)建Buffer

  • 我們可以直接對buffer實例以數(shù)組的形式對每一位進(jìn)行修改

    • 如果修改的是一個十進(jìn)制數(shù)字,那它會自動幫助我們轉(zhuǎn)化成16進(jìn)制的數(shù)字

    • 如果修改的是一個十六進(jìn)制數(shù)字,那么就會直接寫入

// 其可以指定我們buffer的位數(shù),比如這里傳遞進(jìn)去的是8,那么創(chuàng)建出來的buffer就有8個元素,且每個元素對應(yīng)的二進(jìn)制數(shù)都是0
const buffer = Buffer.alloc(8)
console.log(buffer); // <Buffer 00 00 00 00 00 00 00 00>
// 賦值為十進(jìn)制數(shù)字的話,buffer會幫我們轉(zhuǎn)化為16進(jìn)制數(shù)字再寫入到對應(yīng)的位置
buffer[0] = 88 
// 在js中,以0x開頭的就表示為16進(jìn)制的數(shù)字
buffer[1] = 0x88
console.log(buffer); // <Buffer 58 88 00 00 00 00 00 00>

Buffer和文件操作

1、文本文件

  • 如果未指定字符編碼,則不進(jìn)行解碼,直接返回原始的 buffer,也就是文件內(nèi)容結(jié)果utf-8編碼后的二進(jìn)制數(shù)

const fs = require('fs')
fs.readFile('./a.txt', (err, data) => {
  console.log(data); // <Buffer e5 93 88 e5 93 88>
})
  • 編碼和解碼用的都是utf-8,則可以得到文件中正確的內(nèi)容

const fs = require('fs')
// encoding表示解碼所用的字符編碼,編碼默認(rèn)為utf-8
fs.readFile('./a.txt', { encoding: 'utf-8' }, (err, data) => {
  console.log(data); // 哈哈
})
  • 如果編碼和解碼所用的字符編碼不同,則最終讀取出來的內(nèi)容會亂碼

const fs = require('fs')
// 編碼用的是utf16le字符編碼,解碼使用的是utf-8格式,肯定是解不是正確的內(nèi)容的
fs.readFile('./a.txt', { encoding: 'utf16le' }, (err, data) => {
  console.log(data); // 鏥袓
})
// 以上代碼和下面代碼類似
const msg = '哈哈'
const buffer = Buffer.from(msg, 'utf-8')
console.log(buffer.toString('utf16le')); // 鏥袓

2、圖片文件

  • 對圖片編碼進(jìn)行拷貝,達(dá)到復(fù)制圖片的目的

    • 讀取圖片的時候不要指定encoding屬性,因為字符編碼只有在讀取文本文件的時候才有用

const fs = require('fs')

fs.readFile('./logo.png', (err, data) => {
  console.log(data); // 打印出來的是圖片文件對應(yīng)的二進(jìn)制編碼
  
  // 我們還可以將圖片編碼寫入到另一個文件當(dāng)中,相當(dāng)于我們將該圖片拷貝了一份
  fs.writeFile('./bar.png', data, err => {
    console.log(err); 
  })
})
  • 對圖片進(jìn)行翻轉(zhuǎn)、裁剪等操作,可以使用sharp這個庫

const sharp = require('sharp')

// 將logo.png這張圖片裁剪成200x300后拷貝到文件bax.png中
sharp('./logo.png')
  .resize(200, 300)
  .toFile('./bax.png', (err, info) => {
    console.log(err);
  })

// 還可以將圖片文件先轉(zhuǎn)為buffer,然后在寫入到文件中,也可以實現(xiàn)拷貝圖片的目的
sharp('./logo.png')
  .resize(300, 300)
  .toBuffer()
  .then(data => {
    fs.writeFile('./baa.png', data, err => {
      console.log(err);
    })
  })

Buffer的創(chuàng)建過程

  • 事實上我們創(chuàng)建Buffer時,并不會頻繁的向操作系統(tǒng)申請內(nèi)存,它會默認(rèn)先申請一個8 * 1024 個字節(jié)大小的內(nèi)存,也就是8kb

  • 等到內(nèi)存不夠或者快用完的時候才會去申請新的內(nèi)存

事件循環(huán)和異步IO


什么是事件循環(huán)?

  • 事件循環(huán)是什么?

    • 事實上我把事件循環(huán)理解成我們編寫的JS和瀏覽器或者Node之間的一個橋梁

  • 瀏覽器的事件循環(huán)是一個我們編寫的JS代碼和瀏覽器API調(diào)用(setTimeout、AJAX、監(jiān)聽事件等)的一個橋梁,橋梁之間通過回調(diào)函數(shù)進(jìn)行溝通

  • Node的事件循環(huán)是一個我們編寫的JS代碼和系統(tǒng)調(diào)用(file system、networ等)之間的一個橋梁,,橋梁之間也是通過回調(diào)函數(shù)進(jìn)行溝通的

Node.js中的Buffer和事件循環(huán)實例分析

進(jìn)程和線程

進(jìn)程和線程是操作系統(tǒng)中的兩個概念:

  • 進(jìn)程(process):計算機已經(jīng)運行的程序

  • 線程(thread):操作系統(tǒng)能夠運行運算調(diào)度的最小單位,所以CPU能夠直接操作線程

聽起來很抽象,我們直觀一點解釋:

  • 進(jìn)程:我們可以認(rèn)為,啟動一個應(yīng)用程序,就會默認(rèn)啟動一個進(jìn)程(也可能是多個進(jìn)程)

  • 線程:每一個進(jìn)程中,都會啟動一個線程用來執(zhí)行程序中的代碼,這個線程被稱之為主線程

  • 所以我們也可以說進(jìn)程是線程的容器

再用一個形象的例子解釋

  • 操作系統(tǒng)類似于一個工廠

  • 工廠中有很多車間,這個車間就是進(jìn)程

  • 每個車間可能有一個以上的工人在工廠,這個工人就是線程

多進(jìn)程多線程開發(fā)

操作系統(tǒng)是如何做到同時讓多個進(jìn)程(邊聽歌、邊寫代碼、邊查閱資料)同時工作呢?

Node.js中的Buffer和事件循環(huán)實例分析

  • 這是因為CPU的運算速度非常快,他可以快速的在多個進(jìn)程之間迅速的切換

  • 當(dāng)我們的進(jìn)程中的線程獲取到時間片時,就可以快速執(zhí)行我們編寫的代碼

  • 對于用戶來說是感受不到這種快速的切換的

Node.js中的Buffer和事件循環(huán)實例分析

瀏覽器和JavaScript

  • 我們經(jīng)常會說JavaScript是單線程的,但是JS的線程應(yīng)該有自己的容器進(jìn)程:瀏覽器或者Node

  • 瀏覽器是一個進(jìn)程嗎,它里面只有一個線程嗎?

    • 目前多數(shù)的瀏覽器其實都是多進(jìn)程的,當(dāng)我們打開一個tab頁面時就會開啟一個新的進(jìn)程,這是為了防止一個頁面卡死而造成所有頁面無法響應(yīng),整個瀏覽器需要強制退出

    • 每個進(jìn)程中又有很多的線程,其中包括執(zhí)行JavaScript代碼的線程

  • 但是JavaScript的代碼執(zhí)行是在一個單獨的線程中執(zhí)行的

    • 這就意味著JS的代碼,在同一時刻只能做一件事

    • 如果這件事是非常耗時的,就以為這當(dāng)前的線程就會被阻塞

JavaScript的執(zhí)行過程

函數(shù)要被壓入函數(shù)調(diào)用棧中后才會被執(zhí)行,下面我們來分析下代碼的執(zhí)行過程

const message = 'Hello World'

console.log(message);

function sum(num1, num2) {
  return num1 + num2
}

function foo() {
  const result = sum(20, 30)
  console.log(result);
}

foo()
  • 我們JS的代碼其實也可以像其它編程語言一樣可以看成是在main函數(shù)中執(zhí)行的

  • 那么首先我們要將main函數(shù)壓入函數(shù)調(diào)用棧中

  • 定義變量message

  • 執(zhí)行log函數(shù),log函數(shù)會被放入到函數(shù)調(diào)用棧中,執(zhí)行完后出棧

  • 調(diào)用foo函數(shù),foo函數(shù)被壓入函數(shù)調(diào)用棧中,但是執(zhí)行過程中又需要調(diào)用sum函數(shù)

  • 所以sum函數(shù)會被壓入到函數(shù)調(diào)用棧中,sum函數(shù)執(zhí)行完畢后出棧

  • 此時foo函數(shù)也得到了sum函數(shù)返回的值,并執(zhí)行了賦值操作,但又遇到了log函數(shù)

  • 所以又要將log函數(shù)壓入到調(diào)用棧,log函數(shù)被執(zhí)行完畢,出棧后foo函數(shù)也執(zhí)行完畢,foo函數(shù)出棧

  • foo函數(shù)執(zhí)行完后,整個js代碼執(zhí)行完畢,main函數(shù)出棧

瀏覽器的事件循環(huán)

如果在執(zhí)行JS代碼的過程中,有異步操作呢?

  • 比如中間我們插入了一個setTimeout的函數(shù)調(diào)用

  • 那么setTimeout這個函數(shù)被放入到調(diào)用棧中,執(zhí)行會立即結(jié)束,并不會阻塞后續(xù)代碼的執(zhí)行

那么,往setTimeout函數(shù)里面?zhèn)魅氲暮瘮?shù)(我們稱之為timer函數(shù)),會在什么時候被執(zhí)行呢?

  • 事實上,setTimeout是調(diào)用了web api,瀏覽器會提前會將回調(diào)函數(shù)存儲起來,在合適的時機,會將timer函數(shù)加入到一個事件隊列中

  • 事件隊列中的函數(shù),會被放入到函數(shù)調(diào)用棧中,在調(diào)用棧中被執(zhí)行

為什么setTimeout不會阻塞代碼的執(zhí)行呢?就是因為瀏覽器里面維護了一個非常非常重要的東西——事件循環(huán)

  • 瀏覽器中會通過某種方式幫助我們保存setTimeout中的回調(diào)函數(shù)的,比較常用的方法就是保存到一個紅黑樹里面

  • 等到setTimeout定時器時間到達(dá)的時候,它就會將我們的timer回調(diào)函數(shù)從保存的地方取出來并放入到事件隊列里面

  • 事件循環(huán)一旦發(fā)現(xiàn)我們的隊列中有東西了,并且當(dāng)前函數(shù)調(diào)用棧是空的,其它同步代碼也執(zhí)行完之后,就會將我們隊列中的回調(diào)函數(shù)依次出列放入到函數(shù)調(diào)用棧中執(zhí)行(隊列中前一個函數(shù)出棧后,下一個函數(shù)才會入棧)

當(dāng)然事件隊列中不一定只有一個事件,比如說在某個過程中用戶點擊了瀏覽器當(dāng)中的某個按鈕,我們可能對這個按鈕的點擊做了一個監(jiān)聽,對應(yīng)了一個回調(diào)函數(shù),那個回調(diào)函數(shù)也會被加入到我們的隊列里面的,執(zhí)行順序按照它們在事件隊列中的順序執(zhí)行。還有我們發(fā)送ajax請求的回調(diào),也是加入到事件隊列里面的

總結(jié):其實事件循環(huán)是一個很簡單的東西,它就是在某一個特殊的情況下,需要去執(zhí)行某一個回調(diào)的時候,它就把提前保存好的回調(diào)塞入事件隊列里面,事件循環(huán)再給它取出來放入到函數(shù)調(diào)用棧中

Node.js中的Buffer和事件循環(huán)實例分析

宏任務(wù)與微任務(wù)

但是事件循環(huán)中并非只維護一個隊列,事實上是有兩個隊列,而且隊列中的任務(wù)執(zhí)行一定會等到所有的script都執(zhí)行完畢后

  • 宏任務(wù)隊列(macrotask queue):ajax、setTimeout、setInterval、DOM監(jiān)聽、UI Rendering

  • 微任務(wù)隊列(microtask queue):Promisethen回調(diào)、Mutation Observer API、queueMicrotask()

那么事件循環(huán)對于兩個隊列的優(yōu)先級是怎么樣的呢?

  • main script中的代碼優(yōu)先執(zhí)行(編寫的頂層script代碼)

  • 在執(zhí)行任何一個宏任務(wù)之前(不是隊列,是一個宏任務(wù)),都會先查看微任務(wù)隊列中是否有任務(wù)需要執(zhí)行

    • 也就是宏任務(wù)執(zhí)行之前,必須保證微任務(wù)隊列是空的

    • 如果不為空,那么就優(yōu)先執(zhí)行微任務(wù)隊列中的任務(wù)(回調(diào))

面試題<一>

考點:main stcipt、setTimeout、Promisethen、queueMicrotask

setTimeout(() => {
  console.log('set1');4
  new Promise(resolve => {
    resolve()
  }).then(resolve => {
    new Promise(resolve => {
      resolve()
    }).then(() => {
      console.log('then4');
    })
    console.log('then2');
  })
})

new Promise(resolve => {
  console.log('pr1');
  resolve()
}).then(() => {
  console.log('then1');
})

setTimeout(() => {
  console.log('set2');
})

console.log(2);

queueMicrotask(() => {
  console.log('queueMicrotask');
})

new Promise(resolve => {
  resolve()
}).then(() => {
  console.log('then3');
})

// pr1
// 2
// then1
// queueMicrotask
// then3
// set1
// then2
// then4
// set2
  • setTimeout會立即壓入函數(shù)調(diào)用棧,執(zhí)行完畢后立即出棧,其timer函數(shù)被放入到宏任務(wù)隊列中

  • 傳入Promise類的函數(shù)會被立即執(zhí)行,其并不是回調(diào)函數(shù),所以會打印出pr1,并且由于執(zhí)行了resolve方法,所以該Promise的狀態(tài)會立即變?yōu)?code>fulfilled,這樣then函數(shù)執(zhí)行的時候其對應(yīng)的回調(diào)函數(shù)就會被放入到微任務(wù)隊列中

  • 又遇到了一個setTimeout函數(shù),壓棧出棧,其timer函數(shù)會被放入到宏任務(wù)隊列中

  • 遇到console.log語句,函數(shù)壓棧后執(zhí)行打印出了2,然后出棧

  • 這里通過queueMicrotask綁定了個函數(shù),該函數(shù)會被放入到微任務(wù)隊列中

  • 又遇到了new Promise語句,但是其立即就將promise的狀態(tài)改為了fulfilled,所以then函數(shù)對應(yīng)的回調(diào)也被放入到了微任務(wù)隊列中

  • 由于同步腳本代碼已經(jīng)執(zhí)行完畢,現(xiàn)在事件循環(huán)開始要去把微任務(wù)隊列和宏任務(wù)對壘的任務(wù)按照優(yōu)先級順序放入到函數(shù)調(diào)用棧中執(zhí)行了,注意:微任務(wù)的優(yōu)先級比宏任務(wù)高,每次想要執(zhí)行宏任務(wù)之前都要看看微任務(wù)隊列里面是否為空,不為空則需要先執(zhí)行微任務(wù)隊列的任務(wù)

  • 第一個微任務(wù)是打印then1,第二個微任務(wù)是打印queueMicrotask,第三個微任務(wù)是打印then3,執(zhí)行完畢后,就開始去執(zhí)行宏任務(wù)

  • 第一個宏任務(wù)比較復(fù)雜,首先會打印set1,然后執(zhí)行了一個立即變換狀態(tài)的new promise語句,其then回調(diào)會被放入到微任務(wù)隊列中,注意現(xiàn)在微任務(wù)隊列可不是空的,所以需要執(zhí)行優(yōu)先級較高的微任務(wù)隊列,相當(dāng)于該then回調(diào)被立即執(zhí)行了,又是相同的new Promise語句,其對應(yīng)的then對調(diào)被放入到微任務(wù)隊列中,注意new Promise語句后面還有一個console函數(shù),該函數(shù)會在執(zhí)行完new Promise語句后立即執(zhí)行,也就是打印then2,現(xiàn)在微任務(wù)對壘還是有一項任務(wù),所以接下來就是打印then4。目前為止,微任務(wù)隊列已經(jīng)為空了,可以繼續(xù)執(zhí)行宏任務(wù)隊列了

  • 所以接下里的宏任務(wù)set2會被打印,宏任務(wù)執(zhí)行完畢

  • 整個代碼的打印結(jié)果是:pr1 -> 2 -> then1 -> queueMicrotask -> then3 -> set1 -> then2 -> then4 -> set2

面試題<二>

考點:main script、setTimeoutPromise、then、queueMicrotask、await、async

知識補充:async、await是Promise的一個語法糖,在處理事件循環(huán)問題時

  • 我們可以將await關(guān)鍵字后面執(zhí)行的代碼,看做是包裹在new Promise((resolve,rejcet) => { 函數(shù)執(zhí)行 })中的代碼

  • await語句后面的代碼,可以看做是上一個Promise中的then(res => {函數(shù)執(zhí)行})中的代碼

async function async1() {
  console.log('async1 start');
  await async2()
  console.log('async1 end');
}

async function async2() {
  console.log('async2');
}

console.log('script start');

setTimeout(() => {
  console.log('setTimeout');
}, 0)

async1()

new Promise(resolve => {
  console.log('promise1');
  resolve()
}).then(() => {
  console.log('promise2');
})

console.log('script end');

// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeout
  • 一開始都是函數(shù)的定義,不需要壓入函數(shù)調(diào)用棧中執(zhí)行,直到遇到第一個console語句,壓棧后執(zhí)行打印script start后出棧

  • 遇到第一個setTimeout函數(shù),其對應(yīng)的timer會被放入到宏任務(wù)隊列中

  • async1函數(shù)被執(zhí)行,首先打印出async1 start,然后又去執(zhí)行await語句后面的async2函數(shù),因為前面也說了,將await關(guān)鍵字后面的函數(shù)看成是new Promise里面的語句,這個函數(shù)是會被立即執(zhí)行的,所以async2會被打印出來,但該await語句后面的代碼相當(dāng)于是放入到then回調(diào)中的,也就是說console.log('async1 end')這行代碼被放入到了微任務(wù)隊列里

  • 代碼繼續(xù)執(zhí)行,又遇到了一個new Promise語句,所以立即打印出了promise1,then回調(diào)中的函數(shù)被放入到了微任務(wù)隊列里面去

  • 最后一個console函數(shù)執(zhí)行打印script end,同步代碼也就執(zhí)行完畢了,事件循環(huán)要去宏任務(wù)和微任務(wù)隊列里面執(zhí)行任務(wù)了

  • 首先是去微任務(wù)隊列,第一個微任務(wù)對應(yīng)的打印語句會被執(zhí)行,也就是說async1 end會被打印,然后就是promise2被打印,此時微任務(wù)隊列已經(jīng)為空,開始去執(zhí)行宏任務(wù)隊列中的任務(wù)了

  • timer函數(shù)對應(yīng)的setTimeout會被打印,此時宏任務(wù)也執(zhí)行完畢,最終的打印順序是:script start -> async1 start -> async2 -> promise1 -> script end -> async1 end -> promise2 -> setTimeout

以上就是關(guān)于“Node.js中的Buffer和事件循環(huán)實例分析”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

標(biāo)題名稱:Node.js中的Buffer和事件循環(huán)實例分析
瀏覽地址:http://www.muchs.cn/article40/ghgceo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、軟件開發(fā)、網(wǎng)站改版、建站公司、網(wǎng)站導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)