欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

Node.js中回調(diào)隊(duì)列的案例分析-創(chuàng)新互聯(lián)

這篇文章給大家分享的是有關(guān)Node.js中回調(diào)隊(duì)列的案例分析的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考。一起跟隨小編過來看看吧。

為白云等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及白云網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為網(wǎng)站建設(shè)、做網(wǎng)站、白云網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!

隊(duì)列是 Node.js 中用于有效處理異步操作的一項(xiàng)重要技術(shù)。

在本文中,我們將深入研究 Node.js 中的隊(duì)列:它們是什么,它們?nèi)绾喂ぷ鳎ㄍㄟ^事件循環(huán))以及它們的類型。

Node.js 中的隊(duì)列是什么?

隊(duì)列是 Node.js 中用于組織異步操作的數(shù)據(jù)結(jié)構(gòu)。這些操作以不同的形式存在,包括HTTP請求、讀取或?qū)懭胛募僮?、流等?/p>

在 Node.js 中處理異步操作非常具有挑戰(zhàn)性。

HTTP 請求期間可能會出現(xiàn)不可預(yù)測的延遲(或者更糟糕的可能性是沒有結(jié)果),具體取決于網(wǎng)絡(luò)質(zhì)量。嘗試用 Node.js 讀寫文件時(shí)也有可能會產(chǎn)生延遲,具體取決于文件的大小。

類似于計(jì)時(shí)器和其他的許多操作,異步操作完成的時(shí)間也有可能是不確定的。

在這些不同的延遲情況之下,Node.js 需要能夠有效地處理所有這些操作。

Node.js 無法處理基于 first-start-first-handle (先開始先處理)或 first-finish-first-handle (先結(jié)束先處理)的操作。

之所以不能這樣做的一個(gè)原因是,在一個(gè)異步操作中可能還會包含另一個(gè)異步操作。

為第一個(gè)異步過程留出空間意味著必須先要完成內(nèi)部異步過程,然后才能考慮隊(duì)列中的其他異步操作。

有許多情況需要考慮,因此最好的選擇是制定規(guī)則。這個(gè)規(guī)則影響了事件循環(huán)和隊(duì)列在 Node.js 中的工作方式。

讓我們簡要地看一下 Node.js 是怎樣處理異步操作的。

調(diào)用棧,事件循環(huán)和回調(diào)隊(duì)列

調(diào)用棧被用于跟蹤當(dāng)前正在執(zhí)行的函數(shù)以及從何處開始運(yùn)行。當(dāng)一個(gè)函數(shù)將要執(zhí)行時(shí),它會被添加到調(diào)用堆棧中。這有助于 JavaScript 在執(zhí)行函數(shù)后重新跟蹤其處理步驟。

回調(diào)隊(duì)列是在后臺操作完成時(shí)把回調(diào)函數(shù)保存為異步操作的隊(duì)列。它們以先進(jìn)先出(FIFO)的方式工作。我們將會在本文后面介紹不同類型的回調(diào)隊(duì)列。

請注意,Node.js 負(fù)責(zé)所有異步活動,因?yàn)?JavaScript 可以利用其單線程性質(zhì)來阻止產(chǎn)生新的線程。

在完成后臺操作后,它還負(fù)責(zé)向回調(diào)隊(duì)列添加函數(shù)。 JavaScript 本身與回調(diào)隊(duì)列無關(guān)。同時(shí)事件循環(huán)會連續(xù)檢查調(diào)用棧是否為空,以便可以從回調(diào)隊(duì)列中提取一個(gè)函數(shù)并添加到調(diào)用棧中。事件循環(huán)僅在執(zhí)行所有同步操作之后才檢查隊(duì)列。

那么,事件循環(huán)是按照什么樣的順序從隊(duì)列中選擇回調(diào)函數(shù)的呢?

首先,讓我們看一下回調(diào)隊(duì)列的五種主要類型。

回調(diào)隊(duì)列的類型

IO 隊(duì)列(IO queue)

IO操作是指涉及外部設(shè)備(如計(jì)算機(jī)的硬盤、網(wǎng)卡等)的操作。常見的操作包括讀寫文件操作、網(wǎng)絡(luò)操作等。這些操作應(yīng)該是異步的,因?yàn)樗鼈兞艚o Node.js 處理。

JavaScript 無法訪問計(jì)算機(jī)的內(nèi)部設(shè)備。當(dāng)執(zhí)行此類操作時(shí),JavaScript 會將其傳輸?shù)?Node.js 以在后臺處理。

完成后,它們將會被轉(zhuǎn)移到 IO 回調(diào)隊(duì)列中,來進(jìn)行事件循環(huán),以轉(zhuǎn)移到調(diào)用棧中執(zhí)行。

計(jì)時(shí)器隊(duì)列(Timer queue)

每個(gè)涉及 Node.js 計(jì)時(shí)器功能的操作(如 setTimeout()setInterval())都是要被添加到計(jì)時(shí)器隊(duì)列的。

請注意,JavaScript 語言本身沒有計(jì)時(shí)器功能。它使用 Node.js 提供的計(jì)時(shí)器 API(包括 setTimeout )執(zhí)行與時(shí)間相關(guān)的操作。所以計(jì)時(shí)器操作是異步的。無論是 2 秒還是 0 秒,JavaScript 都會把與時(shí)間相關(guān)的操作移交給 Node.js,然后將其完成并添加到計(jì)時(shí)器隊(duì)列中。

例如:

setTimeout(function() {
        console.log('setTimeout');
    }, 0)
    console.log('yeah')


# 返回
yeah
setTimeout

在處理異步操作時(shí),JavaScript 會繼續(xù)執(zhí)行其他操作。只有在所有同步操作都已被處理完畢后,事件循環(huán)才會進(jìn)入回調(diào)隊(duì)列。

微任務(wù)隊(duì)列(Microtask queue)

該隊(duì)列分為兩個(gè)隊(duì)列:

  • 第一個(gè)隊(duì)列包含因 process.nextTick 函數(shù)而延遲的函數(shù)。

事件循環(huán)執(zhí)行的每個(gè)迭代稱為一個(gè) tick(時(shí)間刻度)。

process.nextTick 是一個(gè)函數(shù),它在下一個(gè) tick (即事件循環(huán)的下一個(gè)迭代)執(zhí)行一個(gè)函數(shù)。微任務(wù)隊(duì)列需要存儲此類函數(shù),以便可以在下一個(gè) tick 執(zhí)行它們。

這意味著事件循環(huán)必須繼續(xù)檢查微任務(wù)隊(duì)列中的此類函數(shù),然后再進(jìn)入其他隊(duì)列。

  • 第二個(gè)隊(duì)列包含因 promises 而延遲的函數(shù)。

如你所見,在 IO 和計(jì)時(shí)器隊(duì)列中,所有與異步操作有關(guān)的內(nèi)容都被移交給了異步函數(shù)。

但是 promise 不同。在 promise 中,初始變量存儲在 JavaScript 內(nèi)存中(你可能已經(jīng)注意到了<Pending>)。

異步操作完成后,Node.js 會將函數(shù)(附加到 Promise)放在微任務(wù)隊(duì)列中。同時(shí)它用得到的結(jié)果來更新 JavaScript 內(nèi)存中的變量,以使該函數(shù)不與 <Pending> 一起運(yùn)行。

以下代碼說明了 promise 是如何工作的:

let prom = new Promise(function (resolve, reject) {
        // 延遲執(zhí)行
        setTimeout(function () {
            return resolve("hello");
        }, 2000);
    });
    console.log(prom);
    // Promise { <pending> }
    
    prom.then(function (response) {
        console.log(response);
    });
    // 在 2000ms 之后,輸出
    // hello

關(guān)于微任務(wù)隊(duì)列,需要注意一個(gè)重要功能,事件循環(huán)在進(jìn)入其他隊(duì)列之前要反復(fù)檢查并執(zhí)行微任務(wù)隊(duì)列中的函數(shù)。例如,當(dāng)微任務(wù)隊(duì)列完成時(shí),或者說計(jì)時(shí)器操作執(zhí)行了 Promise 操作,事件循環(huán)將會在繼續(xù)進(jìn)入計(jì)時(shí)器隊(duì)列中的其他函數(shù)之前參與該 Promise 操作。

因此,微任務(wù)隊(duì)列比其他隊(duì)列具有最高的優(yōu)先級。

檢查隊(duì)列(Check queue)

檢查隊(duì)列也稱為即時(shí)隊(duì)列(immediate queue)。IO 隊(duì)列中的所有回調(diào)函數(shù)均已執(zhí)行完畢后,立即執(zhí)行此隊(duì)列中的回調(diào)函數(shù)。setImmediate 用于向該隊(duì)列添加函數(shù)。

例如:

const fs = require('fs');
setImmediate(function() {
    console.log('setImmediate');
})
// 假設(shè)此操作需要 1ms
fs.readFile('path-to-file', function() {
    console.log('readFile')
})
// 假設(shè)此操作需要 3ms
do...while...

執(zhí)行該程序時(shí),Node.js 把 setImmediate 回調(diào)函數(shù)添加到檢查隊(duì)列。由于整個(gè)程序尚未準(zhǔn)備完畢,因此事件循環(huán)不會檢查任何隊(duì)列。

因?yàn)?readFile 操作是異步的,所以會移交給 Node.js,之后程序?qū)^續(xù)執(zhí)行。

do while  操作持續(xù) 3ms。在這段時(shí)間內(nèi),readFile 操作完成并被推送到 IO 隊(duì)列。完成此操作后,事件循環(huán)將會開始檢查隊(duì)列。

盡管首先填充了檢查隊(duì)列,但只有在 IO 隊(duì)列為空之后才考慮使用它。所以在 setImmediate 之前,將 readFile 輸出到控制臺。

關(guān)閉隊(duì)列(Close queue)

此隊(duì)列存儲與關(guān)閉事件操作關(guān)聯(lián)的函數(shù)。

包括以下內(nèi)容:

  • 流關(guān)閉事件,在關(guān)閉流時(shí)發(fā)出。它表示不再發(fā)出任何事件。
  • http關(guān)閉事件,在服務(wù)器關(guān)閉時(shí)發(fā)出。

這些隊(duì)列被認(rèn)為是優(yōu)先級最低的,因?yàn)榇颂幍牟僮鲿谝院蟀l(fā)生。

你肯sing不希望在處理 promise 函數(shù)之前在 close 事件中執(zhí)行回調(diào)函數(shù)。當(dāng)服務(wù)器已經(jīng)關(guān)閉時(shí),promise 函數(shù)會做些什么呢?

隊(duì)列順序

微任務(wù)隊(duì)列具有最高優(yōu)先級,其次是計(jì)時(shí)器隊(duì)列,I/O隊(duì)列,檢查隊(duì)列,最后是關(guān)閉隊(duì)列。

回調(diào)隊(duì)列的例子

讓我們通過一個(gè)更復(fù)雜的例子來說明隊(duì)列的類型和順序:

const fs = require("fs");

// 假設(shè)此操作需要 2ms
fs.writeFile('./new-file.json', '...', function() {
    console.log('writeFile')
})

// 假設(shè)這需要 10ms 才能完成 
fs.readFile("./file.json", function(err, data) {
    console.log("readFile");
});

// 不需要假設(shè),這實(shí)際上需要 1ms
setTimeout(function() {
    console.log("setTimeout");
}, 1000);

// 假設(shè)此操作需要 3ms
while(...) {
    ...
}

setImmediate(function() {
    console.log("setImmediate");
});

// 解決 promise 需要 4 ms
let promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
        return resolve("promise");
    }, 4000);
});
promise.then(function(response) {
    console.log(response)
})

console.log("last line");

程序流程如下:

  • 在 0 毫秒時(shí),程序開始。
  • 在 Node.js 將回調(diào)函數(shù)添加到 IO 隊(duì)列之前,fs.writeFile 在后臺花費(fèi) 2 毫秒。

fs.readFile takes 10ms at the background before Node.js adds the callback function to the IO queue.

  • 在 Node.js 將回調(diào)函數(shù)添加到 IO 隊(duì)列之前,fs.readFile 在后臺花費(fèi) 10 毫秒。
  • 在 Node.js 將回調(diào)函數(shù)添加到計(jì)時(shí)器隊(duì)列之前,setTimeout 在后臺花費(fèi) 1ms。
  • 現(xiàn)在,while 操作(同步)需要 3ms。在此期間,線程被阻止(請記住 JavaScript 是單線程的)。
  • 同樣在這段時(shí)間內(nèi),setTimeoutfs.writeFile 操作完成,并將它們的回調(diào)函數(shù)分別添加到計(jì)時(shí)器和 IO 隊(duì)列中。

現(xiàn)在的隊(duì)列是:

// queues
Timer = [
    function () {
        console.log("setTimeout");
    },
];
IO = [
    function () {
        console.log("writeFile");
    },
];

setImmediate 將回調(diào)函數(shù)添加到 Check 隊(duì)列中:

js
// 隊(duì)列
Timer...
IO...
Check = [
    function() {console.log("setImmediate")}
]

在將 promise 操作添加到微任務(wù)隊(duì)列之前,需要花費(fèi) 4ms 的時(shí)間在后臺進(jìn)行解析。

最后一行是同步的,因此將會立即執(zhí)行:

# 返回
"last line"

因?yàn)樗型交顒佣家淹瓿桑允录h(huán)開始檢查隊(duì)列。由于微任務(wù)隊(duì)列為空,因此它從計(jì)時(shí)器隊(duì)列開始:

// 隊(duì)列
Timer = [] // 現(xiàn)在是空的
IO...
Check...


# 返回
"last line"
"setTimeout"

當(dāng)事件循環(huán)繼續(xù)執(zhí)行隊(duì)列中的回調(diào)函數(shù)時(shí),promise 操作完成并被添加到微任務(wù)隊(duì)列中:

// 隊(duì)列
    Timer = [];
    Microtask = [
        function (response) {
            console.log(response);
        },
    ];
    IO = []; // 當(dāng)前是空的
    Check = []; // 當(dāng)前是在 IO 的后面,為空


    # results
    "last line"
    "setTimeout"
    "writeFile"
    "setImmediate"

幾秒鐘后,readFile 操作完成,并添加到 IO 隊(duì)列中:

// 隊(duì)列
    Timer = [];
    Microtask = []; // 當(dāng)前是空的
    IO = [
        function () {
            console.log("readFile");
        },
    ];
    Check = [];


    # results
    "last line"
    "setTimeout"
    "writeFile"
    "setImmediate"
    "promise"

最后,執(zhí)行所有回調(diào)函數(shù):

// 隊(duì)列
    Timer = []
    Microtask = []
    IO = [] // 現(xiàn)在又是空的
    Check = [];


    # results
    "last line"
    "setTimeout"
    "writeFile"
    "setImmediate"
    "promise"
    "readFile"

這里要注意的三點(diǎn):

  • 異步操作取決于添加到隊(duì)列之前的延遲時(shí)間。并不取決于它們在程序中的存放順序。
  • 事件循環(huán)在每次迭代之繼續(xù)檢查其他任務(wù)之前,會連續(xù)檢查微任務(wù)隊(duì)列。
  • 即使在后臺有另一個(gè) IO 操作(readFile),事件循環(huán)也會執(zhí)行檢查隊(duì)列中的函數(shù)。這樣做的原因是此時(shí) IO 隊(duì)列為空。請記住,在執(zhí)行 IO 隊(duì)列中的所有的函數(shù)之后,將會立即運(yùn)行檢查隊(duì)列回調(diào)。

總結(jié)

JavaScript 是單線程的。每個(gè)異步函數(shù)都由依賴操作系統(tǒng)內(nèi)部函數(shù)工作的 Node.js 去處理。

Node.js 負(fù)責(zé)將回調(diào)函數(shù)(通過 JavaScript 附加到異步操作)添加到回調(diào)隊(duì)列中。事件循環(huán)會確定將要在每次迭代中接下來要執(zhí)行的回調(diào)函數(shù)。

了解隊(duì)列如何在 Node.js 中工作,使你對其有了更好的了解,因?yàn)殛?duì)列是環(huán)境的核心功能之一。 Node.js 最受歡迎的定義是 non-blocking(非阻塞),這意味著異步操作可以被正確的處理。都是因?yàn)橛辛耸录h(huán)和回調(diào)隊(duì)列才能使此功能生效。

感謝各位的閱讀!關(guān)于Node.js中回調(diào)隊(duì)列的案例分析就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

當(dāng)前標(biāo)題:Node.js中回調(diào)隊(duì)列的案例分析-創(chuàng)新互聯(lián)
網(wǎng)站地址:http://aaarwkj.com/article48/cogshp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站、品牌網(wǎng)站設(shè)計(jì)、全網(wǎng)營銷推廣、Google品牌網(wǎng)站建設(shè)、網(wǎng)站導(dǎo)航

廣告

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

h5響應(yīng)式網(wǎng)站建設(shè)
日本亚洲美丽少妇天堂| 国产精品色网在线播放| 无码精品人妻一区二区三区中| 亚洲欧美久久一区二区三区 | 女同欲望一区二区三区久久| 国产精品亚洲欧美日韩在线播放| 日本色小姐美国青青草原| 亚洲日本国产一区二区| 亚洲男女尻逼片视频网站| 91国内精品手机在线高清| 99国产综合精品女| 精品人妻av中文字幕乱| 91麻豆精品国产91久5久久| 亚洲国产中日韩精品综合| 亚洲精品精品一区二区| 国产九色91中文在线视频| 亚洲国产香蕉视频在线播放| 久久国产高清亚洲电影| 欧美亚洲综合日韩精品区| 亚洲av污精品一区二区三区| 中文字幕成人乱码亚洲| 久久久久久精品国产免费| 欧美aⅴ一区二区三区| 国产精品一区二区三区欧美| 亚洲综合av一区二区| 国产精品久久久久精品日日三级| 国产特级黄色片免费看| 少妇诱惑一区二区三区| 最新中文字幕成人在线观看| 亚洲国产理论片在线观看| 中高龄夫妇五十路六十路| 亚洲熟妇中文字幕五十中出| 日本中文字幕一二三四区| 日韩视频一区二区三区四区| 久久91亚洲精品中文字幕| 午夜射精视频在线观看| 亚洲女同中文字幕在线| 日本毛茸茸的丰满熟妇| 91香蕉国产精品日韩| 日韩欧美乱码一区二区| 人妻在线中文字幕一区|