日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

這次,徹底理解 JavaScript 的執(zhí)行機制

來源: 責編: 時間:2024-06-21 17:25:23 245觀看
導讀無論你是 JavaScript 的初學者還是專家,無論是為了求職面試還是日常開發(fā)工作,我們經常會遇到這樣的情況:給出幾行代碼,我們需要知道它們的輸出內容和順序。由于 JavaScript 是一種單線程語言,我們可以得出以下結論:JavaScri

v5228資訊網——每日最新資訊28at.com

無論你是 JavaScript 的初學者還是專家,無論是為了求職面試還是日常開發(fā)工作,我們經常會遇到這樣的情況:給出幾行代碼,我們需要知道它們的輸出內容和順序。由于 JavaScript 是一種單線程語言,我們可以得出以下結論:v5228資訊網——每日最新資訊28at.com

JavaScript 按照語句出現的順序執(zhí)行。v5228資訊網——每日最新資訊28at.com

此時,讀者可能會說:我知道 JS 是一行一行執(zhí)行的,為什么還要特別指出呢?冷靜下來;正因為 JS 是一行一行執(zhí)行的,我們假設所有的 JS 都是這樣工作的:v5228資訊網——每日最新資訊28at.com

let a = '1';console.log(a);let b = '2';console.log(b);

然而,實際上 JS 是這樣的:v5228資訊網——每日最新資訊28at.com

setTimeout(function(){  console.log('定時器開始了')});new Promise(function(resolve){  console.log('即將執(zhí)行for循環(huán)');  for(var i = 0; i < 10000; i++){    i == 99 && resolve();  }}).then(function(){  console.log('執(zhí)行then函數')});console.log('代碼執(zhí)行結束');

遵循 JavaScript 按語句順序執(zhí)行的概念,我自信地寫下了輸出:v5228資訊網——每日最新資訊28at.com

  • 定時器開始了。
  • 即將執(zhí)行for循環(huán)。
  • 執(zhí)行then函數。
  • 代碼執(zhí)行結束。

然而,在 Chrome 中驗證時,結果完全錯誤,瞬間迷惑,難道不是按約定的一行一行執(zhí)行的嗎?v5228資訊網——每日最新資訊28at.com

我們需要徹底理解 JavaScript 的執(zhí)行機制。v5228資訊網——每日最新資訊28at.com

關于 JavaScript

JavaScript 是一種單線程語言。盡管在最新的 HTML5 中引入了 Web Worker,但 JavaScript 的單線程核心沒有改變。因此,JavaScript 中的所有“多線程”都是使用單線程模擬的,所有的多線程都是欺騙性的!v5228資訊網——每日最新資訊28at.com

JavaScript 事件循環(huán)

由于 JavaScript 是單線程的,就像只有一個窗口的銀行,客戶需要一個接一個地排隊辦理業(yè)務。同樣,JavaScript 任務也需要一個接一個地執(zhí)行。如果一個任務花費太長時間,那么下一個任務就必須等待。所以問題來了:如果我們想瀏覽新聞,但新聞中的高清圖片加載緩慢,我們的網頁是否必須一直卡住,直到圖片完全顯示?因此,聰明的程序員將任務分為兩類:v5228資訊網——每日最新資訊28at.com

  • 同步任務
  • 異步任務

當我們打開一個網站時,網頁的渲染過程由一堆同步任務組成,如渲染頁面骨架和頁面元素。那些消耗資源多、耗時長的任務,如加載圖片或音樂文件,則是異步任務。為了簡化理解,我們使用思維導圖來說明這一點:v5228資訊網——每日最新資訊28at.com

v5228資訊網——每日最新資訊28at.com

如果用文字描述思維導圖的內容:v5228資訊網——每日最新資訊28at.com

  • 同步任務和異步任務進入不同的執(zhí)行“場所”,同步任務進入主線程,異步任務進入事件表并注冊函數。
  • 當指定任務完成時,事件表會將這個函數移動到事件隊列中。
  • 主線程中的任務執(zhí)行完畢后,會從事件隊列中讀取相應的函數并在主線程中執(zhí)行。
  • 上述過程會不斷重復,這通常被稱為事件循環(huán)(Event Loop)。

我們不禁要問,如何知道主線程執(zhí)行棧是否為空?JavaScript 引擎有一個監(jiān)視過程,持續(xù)檢查主線程執(zhí)行棧是否為空。一旦為空,它就會去事件隊列中檢查是否有等待調用的函數。v5228資訊網——每日最新資訊28at.com

經過以上描述,一段代碼可能會更直觀:v5228資訊網——每日最新資訊28at.com

let data = [];$.ajax({    url: 'www.javascript.com',    data: data,    success: () => {        console.log('發(fā)送成功');    }})console.log('代碼執(zhí)行結束');

上面是一段簡單的 ajax 請求代碼:v5228資訊網——每日最新資訊28at.com

  • ajax 進入事件表并注冊回調函數 success。
  • 執(zhí)行 console.log('代碼執(zhí)行結束')。
  • ajax 事件完成,回調函數 success 進入事件隊列。
  • 主線程從事件隊列中讀取并執(zhí)行回調函數 success。

通過以上的文字和代碼,相信你對 JavaScript 的執(zhí)行順序有了初步的了解。接下來,讓我們研究一個高級話題:setTimeoutv5228資訊網——每日最新資訊28at.com

對 setTimeout 的愛恨情仇

眾所周知,setTimeout 無需過多介紹。我們對它的第一印象是它可以在延遲之后異步執(zhí)行。我們經常使用它來實現 3 秒延遲執(zhí)行:v5228資訊網——每日最新資訊28at.com

setTimeout(() => {    task();}, 3000)console.log('執(zhí)行 console');

隨著 setTimeout 的使用逐漸增多,問題也隨之而來。有時,即使在代碼中指定了 3 秒的延遲,函數也會在 5 或 6 秒后執(zhí)行。這可能是什么原因造成的呢?v5228資訊網——每日最新資訊28at.com

我們先看一個例子:v5228資訊網——每日最新資訊28at.com

setTimeout(() => {    task();}, 3000)console.log('執(zhí)行 console');

根據我們之前的結論,setTimeout 是異步的,所以同步任務 console.log 應該先執(zhí)行。因此,我們的結論是:v5228資訊網——每日最新資訊28at.com

  • 執(zhí)行 console
  • task()

為了驗證,結果是正確的!然后讓我們對之前的代碼做一些修改:v5228資訊網——每日最新資訊28at.com

setTimeout(() => {    task();}, 3000)sleep(10000000)

乍一看,這似乎類似,但當我們在 Chrome 中執(zhí)行這段代碼時,發(fā)現 console 的執(zhí)行時間遠遠超過 3 秒。為什么現在需要這么長時間呢?v5228資訊網——每日最新資訊28at.com

此時,我們需要重新定義 setTimeout。讓我們來討論上面代碼的執(zhí)行過程:v5228資訊網——每日最新資訊28at.com

  • task() 進入事件表并注冊,計時開始。
  • 執(zhí)行非常緩慢的 sleep 函數,計時繼續(xù)。
  • 3 秒鐘過去,計時事件 timeout 完成。task() 進入事件隊列。但是,sleep 太慢,還沒有執(zhí)行完畢;所以我們必須等待。
  • 最后,sleep 執(zhí)行完畢。task() 終于從事件隊列移動到主線程執(zhí)行。

經過上述過程,我們了解到 setTimeout 函數會在指定時間后將任務(在這個例子中是 task())添加到事件隊列中。由于任務在單線程環(huán)境中一個接一個地執(zhí)行,如果前面的任務執(zhí)行時間過長,執(zhí)行時間將顯著超過 3 秒。v5228資訊網——每日最新資訊28at.com

我們經常遇到類似 setTimeout(fn, 0) 的代碼。0 秒后執(zhí)行意味著什么?它能立即執(zhí)行嗎?v5228資訊網——每日最新資訊28at.com

答案是否定的。setTimeout(fn, 0) 的意思是指定某個任務在主線程最早的空閑時間執(zhí)行,不需要等待任何額外的秒數,一旦所有同步任務在棧中完成并且棧變?yōu)榭铡@纾?span style="display:none">v5228資訊網——每日最新資訊28at.com

// 代碼 1console.log('先執(zhí)行這里');setTimeout(() => {    console.log('執(zhí)行了')}, 0);// 代碼 2console.log('先執(zhí)行這里');setTimeout(() => {    console.log('執(zhí)行了')}, 3000);

代碼 1 的輸出結果是:v5228資訊網——每日最新資訊28at.com

  • 先執(zhí)行這里
  • 執(zhí)行了

代碼 2 的輸出結果是:v5228資訊網——每日最新資訊28at.com

  • 先執(zhí)行這里
  • ... 3 秒后
  • 執(zhí)行了

關于 setTimeout 需要注意的是,即使主線程空閑,0 毫秒也無法實現。根據 HTML 標準,最小值為 4 毫秒。感興趣的同學可以自行探索。v5228資訊網——每日最新資訊28at.com

雙胞胎兄弟 setInterval

談到 setTimeout,我們不能錯過它的雙胞胎兄弟 setInterval。它們很相似,只不過后者是循環(huán)執(zhí)行的。從執(zhí)行順序來看,setInterval 會在每個指定的間隔時間將注冊的函數放入事件隊列。如果前一個任務花費太長時間,它也需要等待。v5228資訊網——每日最新資訊28at.com

唯一需要注意的是,對于 setInterval(fn, ms),我們已經知道 fn 不會每 ms 秒執(zhí)行一次,而是在每 ms 秒將一個新的 fn 實例放入事件隊列。如果 setInterval 的回調函數(fn)花費的時間超過了延遲時間(ms),那么將不會有明顯的時間間隔。請仔細思考這句話。v5228資訊網——每日最新資訊28at.com

Promise 和 process.nextTick(callback)

我們已經研究了傳統(tǒng)的定時器,接下來,我們將探索 Promise 和 process.nextTick(callback) 的表現。v5228資訊網——每日最新資訊28at.com

Promise 的定義和功能在本文中不會詳細展開。而 process.nextTick(callback) 類似于 Node.js 中的 “setTimeout”,在事件循環(huán)的下一輪調用回調函數。v5228資訊網——每日最新資訊28at.com

切入正題,除了同步任務和異步任務的廣義定義外,我們還有更精細的任務定義:v5228資訊網——每日最新資訊28at.com

  • 宏任務(macro-task):包括整體代碼、setTimeout、setInterval
  • 微任務(micro-task):Promise、process.nextTick

不同類型的任務將進入相應的事件隊列;例如,setTimeout 和 setInterval 將進入同一個事件隊列。v5228資訊網——每日最新資訊28at.com

事件循環(huán)中的事件順序決定了 JavaScript 代碼的執(zhí)行順序。在進入整體代碼(宏任務)后,它開始其第一次循環(huán)。然后,它執(zhí)行所有的微任務。接下來,它再次從宏任務開始,直到一個任務隊列完成,再次執(zhí)行所有的微任務。聽起來有點復雜;讓我們用本文前面的一個代碼片段來說明:v5228資訊網——每日最新資訊28at.com

setTimeout(function() {    console.log('setTimeout');})new Promise(function(resolve) {    console.log('promise');}).then(function() {    console.log('then');})console.log('console');
  • 這段代碼作為宏任務進入主線程。
  • 遇到 setTimeout,它的回調函數被注冊并分派到宏任務事件隊列中。
  • 接下來,遇到 Promise,new Promise 立即執(zhí)行,并將 then 函數分派到微任務事件隊列中。
  • 遇到 console.log(),立即執(zhí)行。
  • 在作為第一個宏任務執(zhí)行整體代碼后,我們看看有哪些微任務。我們發(fā)現 then 在微任務事件隊列中,并執(zhí)行它。
  • 事件循環(huán)的第一輪結束。讓我們從宏任務事件隊列開始第二輪循環(huán)。我們發(fā)現這個隊列中對應于 setTimeout 的回調函數立即執(zhí)行。
  • 結束

事件循環(huán)、宏任務和微任務之間的關系如圖所示:v5228資訊網——每日最新資訊28at.com

v5228資訊網——每日最新資訊28at.com

我們分析一段更復雜的代碼,看看您是否理解了 JavaScript 的執(zhí)行機制:v5228資訊網——每日最新資訊28at.com

console.log('1');setTimeout(function() {    console.log('2');    process.nextTick(function() {        console.log('3');    })    new Promise(function(resolve) {        console.log('4');        resolve();    }).then(function() {        console.log('5')    })})process.nextTick(function() {    console.log('6');})new Promise(function(resolve) {    console.log('7');    resolve();}).then(function() {    console.log('8')})setTimeout(function() {    console.log('9');    process.nextTick(function() {        console.log('10');    })    new Promise(function(resolve) {        console.log('11');        resolve();    }).then(function() {        console.log('12')    })})

事件循環(huán)第一輪過程分析如下:v5228資訊網——每日最新資訊28at.com

  • 整體代碼作為第一個宏任務進入主線程,遇到 console.log 并輸出 1。
  • 遇到 setTimeout,它的回調函數被分派到宏任務事件隊列中,我們暫時稱之為 setTimeout1。
  • 遇到 process.nextTick(),它的回調函數被分派到微任務事件隊列中,我們稱之為 process1。
  • 遇到 Promise,new Promise 直接執(zhí)行并輸出 7,then 方法分派到微任務事件隊列中,我們稱之為 then1。
  • 再次遇到 setTimeout,它的回調函數被分派到宏任務事件隊列中,我們稱之為 setTimeout2。

v5228資訊網——每日最新資訊28at.com

  • 在事件循環(huán)宏任務第一輪結束時,輸出 1 和 7。
  • 我們發(fā)現兩個微任務:process1 和 then1。
  • 執(zhí)行 process1 輸出 6。
  • 執(zhí)行 then1 輸出 8。

第一輪事件循環(huán)正式結束,結果輸出為 1, 7, 6, 8。第二輪事件循環(huán)從 setTimeout1 宏任務開始:v5228資訊網——每日最新資訊28at.com

  • 首先,輸出 2。接下來,遇到 process.nextTick(),將其分派到微任務事件隊列中,標記為 process2。new Promise 立即執(zhí)行并輸出 4,然后分派到微任務事件隊列中,標記為 then2。

v5228資訊網——每日最新資訊28at.com

  • 在第二輪事件循環(huán)宏任務結束后,我們發(fā)現有兩個微任務,process2 和 then2,可以執(zhí)行。
  • 輸出 3。
  • 輸出 5。
  • 第二輪事件循環(huán)結束,輸出為 2, 4, 3, 5。
  • 第三輪事件循環(huán)開始,此時只有 setTimeout2 剩下等待執(zhí)行。
  • 直接輸出 9。
  • 分派 process.nextTick() 到微任務事件隊列,標記為 process3。
  • new Promise 直接執(zhí)行并輸出 11。
  • 分派 then 到微任務事件隊列,標記為 then3。

v5228資訊網——每日最新資訊28at.com

  • 第三輪事件循環(huán)宏任務執(zhí)行完成,執(zhí)行兩個微任務 process3 和 then3。
  • 輸出 10。
  • 輸出 12。
  • 第三輪事件循環(huán)結束,輸出為 9, 11, 10, 12。

整個代碼段經過了三輪事件循環(huán),完整輸出為 1, 7, 6, 8, 2, 4, 3, 5, 9, 11, 10, 12。v5228資訊網——每日最新資訊28at.com

在 Node 環(huán)境中的事件監(jiān)聽依賴于 libuv,與前端環(huán)境不完全相同,輸出順序可能會有差異。v5228資訊網——每日最新資訊28at.com

總結

JavaScript 的異步性:從一開始,我們就說過 JavaScript 是單線程語言。無論使用什么新框架或語法糖來實現所謂的異步性,都是通過同步方法模擬的。牢牢把握單線程這一點非常重要。v5228資訊網——每日最新資訊28at.com

事件循環(huán):事件循環(huán)是 JavaScript 實現異步操作的方法,也是其執(zhí)行機制。v5228資訊網——每日最新資訊28at.com

JavaScript 的執(zhí)行與運行:執(zhí)行和運行有很大區(qū)別。JavaScript 的執(zhí)行方式在不同環(huán)境中有所不同,如 Node.js、瀏覽器、Ringo 等。然而,運行大多指 JavaScript 解析引擎,保持一致。v5228資訊網——每日最新資訊28at.com

setImmediate:有許多類型的微任務和宏任務,如 setImmediate 等,它們的執(zhí)行有共同點。感興趣的同學可以自行探索。v5228資訊網——每日最新資訊28at.com

最后但同樣重要的是:JavaScript 是單線程語言,事件循環(huán)是其執(zhí)行機制。 牢牢掌握這兩個基本點,認真學習 JavaScript,很快實現成為優(yōu)秀前端開發(fā)者的偉大夢想!v5228資訊網——每日最新資訊28at.com

本文鏈接:http://m.www897cc.com/showinfo-26-95556-0.html這次,徹底理解 JavaScript 的執(zhí)行機制

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 如何更改 .NET 中的默認時區(qū)?

下一篇: 接口性能優(yōu)化的11個小技巧

標簽:
  • 熱門焦點
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
国产视频一区三区| 免费在线观看日韩欧美| 日韩性生活视频| 一本不卡影院| 亚洲欧美日韩在线高清直播| 欧美一区在线看| 久久蜜桃av一区精品变态类天堂| 免费观看亚洲视频大全| 欧美日韩精品三区| 国产精品一区二区三区乱码| 好吊视频一区二区三区四区| 亚洲人成啪啪网站| 亚洲自拍偷拍网址| 久久久999精品视频| 欧美大片18| 国产精品嫩草久久久久| 韩日精品视频一区| 日韩视频一区二区三区| 欧美一级大片在线免费观看| 美女日韩欧美| 欧美午夜片欧美片在线观看| 韩日欧美一区二区三区| 99视频日韩| 久久久国产精彩视频美女艺术照福利| 欧美国产激情| 国产日韩欧美在线| 亚洲精品一区二区三区99| 午夜在线精品| 欧美激情中文字幕一区二区 | 欧美日韩精品中文字幕| 国产欧美91| 亚洲人成77777在线观看网| 午夜一级久久| 欧美日韩精品免费在线观看视频| 国产一区二区三区网站| 一区二区三区日韩在线观看| 久久久久久久久久看片| 国产精品久久久久久久久借妻 | 国产欧美在线| 日韩特黄影片| 麻豆久久婷婷| 国产亚洲毛片在线| 亚洲一区二区视频| 欧美电影资源| 激情av一区二区| 午夜亚洲精品| 欧美午夜精品| 亚洲麻豆av| 麻豆91精品91久久久的内涵| 国产日本欧美一区二区| 在线亚洲欧美专区二区| 欧美肥婆在线| 一区二区三区在线免费播放| 亚洲欧美综合v| 欧美四级电影网站| 日韩视频一区二区在线观看| 久久免费99精品久久久久久| 国产欧美日韩综合精品二区| 亚洲一二三级电影| 欧美日韩福利在线观看| 亚洲国产成人高清精品| 久久久久国色av免费观看性色| 国产精品实拍| 亚洲伊人第一页| 欧美午夜精品久久久| 亚洲精品一区二区三区樱花| 美女日韩在线中文字幕| 黄色工厂这里只有精品| 欧美在线视频全部完| 国产精品一区二区在线观看不卡| 一区二区冒白浆视频| 欧美人成在线| 亚洲精品一区二区网址| 欧美激情bt| 亚洲国产专区| 国产精品揄拍500视频| 一本大道久久精品懂色aⅴ| 欧美激情第9页| 亚洲高清网站| 免费不卡欧美自拍视频| 亚洲第一中文字幕| 免费成人av| 亚洲激情社区| 欧美精品乱码久久久久久按摩| 亚洲人成人99网站| 欧美激情免费观看| 亚洲美女91| 欧美日韩天堂| 亚洲一区欧美| 国产精品一区在线观看你懂的| 亚洲欧美一区二区三区极速播放| 国产精品区一区二区三| 香蕉久久一区二区不卡无毒影院| 国产精品丝袜久久久久久app| 午夜宅男久久久| 国产真实久久| 久久夜色精品国产噜噜av| 曰本成人黄色| 欧美国产日韩二区| 一本大道久久a久久精品综合| 欧美色播在线播放| 午夜国产欧美理论在线播放| 国产午夜一区二区三区| 久久久免费观看视频| 亚洲国产精品999| 欧美精品三级在线观看| 亚洲视频欧美视频| 国产乱理伦片在线观看夜一区 | 另类国产ts人妖高潮视频| 亚洲国产精品一区| 欧美日韩国产美女| 午夜精品久久久久久| 精品动漫3d一区二区三区| 欧美成人一区二区三区在线观看 | 亚洲在线视频网站| 国产一区二区你懂的| 欧美成人黑人xx视频免费观看| 99re6热只有精品免费观看| 国产精品美女久久久| 欧美在线一二三区| 亚洲国产成人一区| 欧美性生交xxxxx久久久| 久久精品盗摄| 欧美mv日韩mv亚洲| 在线亚洲一区观看| 国产亚洲精品自拍| 欧美大片一区二区| 亚洲欧美日韩国产一区| 永久555www成人免费| 欧美日韩亚洲91| 久久精品国产99国产精品| 亚洲黑丝在线| 国产精品日韩一区二区三区| 久久亚洲私人国产精品va| 一本大道久久a久久精二百| 国产亚洲欧美日韩日本| 欧美精品一区二区三区久久久竹菊| 亚洲一二三区在线| 亚洲国产中文字幕在线观看| 国产精品卡一卡二| 另类尿喷潮videofree| 亚洲一区二区三区在线| 亚洲国产成人porn| 国产欧美精品在线| 欧美精品一卡二卡| 久久久久国产精品厨房| 亚洲一二三四久久| 亚洲国产日本| 国产午夜精品久久久久久免费视| 欧美另类高清视频在线| 欧美在线播放| 一区二区三区www| 亚洲福利在线看| 国产精品午夜国产小视频| 欧美精品日韩精品| 久久久免费av| 亚洲免费一级电影| 亚洲三级影院| 一区二区在线观看视频在线观看| 国产精品国产a级| 欧美大片va欧美在线播放| 久久福利视频导航| 亚洲一区二区精品在线| 亚洲精品免费在线播放| 国内一区二区三区在线视频| 国产精品地址| 欧美韩日一区二区三区| 久久久久久久久综合| 欧美亚洲午夜视频在线观看| 一本色道久久加勒比精品| 亚洲高清不卡在线观看| 国内欧美视频一区二区| 国产欧美精品在线| 国产精品美女视频网站| 欧美日韩一区二区三区免费| 欧美成人免费观看| 免费在线国产精品| 久久综合九九| 久久精品一本| 欧美与黑人午夜性猛交久久久| 亚洲性夜色噜噜噜7777| 一区二区三区欧美亚洲| 亚洲精品免费看| 亚洲国产天堂久久综合网| 精品福利电影| 狠狠综合久久av一区二区老牛| 国产精品伊人日日| 国产精品乱子久久久久| 欧美三日本三级少妇三2023| 欧美日韩免费观看一区| 欧美人交a欧美精品| 欧美精品亚洲精品| 欧美人与性动交a欧美精品| 欧美成人综合网站| 欧美成人综合| 欧美激情第8页| 欧美激情综合五月色丁香| 美日韩精品免费观看视频| 裸体丰满少妇做受久久99精品| 久久亚洲一区| 玖玖在线精品| 农夫在线精品视频免费观看| 欧美96在线丨欧| 欧美激情精品久久久|