日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

JavaScript異步編程

瀏覽:71日期:2023-11-14 08:13:59

還記得一年前寫過一篇關于 JavaScript異步編程簡述 的文章,主要介紹了JavaScript的單線程特性與異步編程實現方式:

回調函數,發布訂閱模式,Promise對象三種,關于Promise介紹的比較簡略,決定再詳細總結一下,既是對上一篇文章的補充,也能以更深刻的方式分享自己關于異步編程的理解。

前言

如果你有志于成為一個優秀的前端工程師,或是想要深入學習JavaScript,異步編程是必不可少的一個知識點,這也是區分初級,中級或高級前端的依據之一。如果你對異步編程沒有太清晰的概念,那么我建議你花點時間學習JavaScript異步編程,如果你對異步編程有自己的獨特理解,也歡迎閱讀本文,一起交流。

同步與異步

介紹異步之前,回顧一下,所謂同步編程,就是計算機一行一行按順序依次執行代碼,當前代碼任務耗時執行會阻塞后續代碼的執行。

同步編程,即是一種典型的請求-響應模型,當請求調用一個函數或方法后,需等待其響應返回,然后執行后續代碼。

一般情況下,同步編程,代碼按序依次執行,能很好的保證程序的執行,但是在某些場景下,比如讀取文件內容,或請求服務器接口數據,需要根據返回的數據內容執行后續操作,讀取文件和請求接口直到數據返回這一過程是需要時間的,網絡越差,耗費時間越長,如果按照同步編程方式實現,在等待數據返回這段時間,JavaScript是不能處理其他任務的,此時頁面的交互,滾動等任何操作也都會被阻塞,這顯然是及其不友好,不可接受的,而這正是需要異步編程大顯身手的場景,如下圖,耗時任務A會阻塞任務B的執行,等到任務A執行完才能繼續執行B:

JavaScript異步編程

當使用異步編程時,在等待當前任務的響應返回之前,可以繼續執行后續代碼,即當前執行任務不會阻塞后續執行。

異步編程,不同于同步編程的請求-響應模式,其是一種 事件驅動編程 ,請求調用函數或方法后,無需立即等待響應,可以繼續執行其他任務,而之前任務響應返回后可以通過狀態、通知和回調來通知調用者。

多線程

前面說明了異步編程能很好的解決同步編程阻塞的問題,那么實現異步的方式有哪些呢?通常實現異步方式是多線程,如C#, 即同時開啟多個線程,不同操作能并行執行,如下圖,耗時任務A執行的同時,在線程二中任務B也可以執行:

JavaScript異步編程

JavaScript單線程

JavaScript語言執行環境是單線程的,單線程在程序執行時,所走的程序路徑按照連續順序排下來,前面的必須處理好,后面的才會執行,而使用異步實現時,多個任務可以并發執行。那么JavaScript的異步編程如何實現呢,下一節將詳細闡述其異步機制。

并行與并發

前文提到多線程的任務可以并行執行,而JavaScript單線程異步編程可以實現多任務并發執行,這里有必要說明一下并行與并發的區別。

并行,指同一時刻內多任務同時進行; 并發,指在同一時間段內,多任務同時進行著,但是某一時刻,只有某一任務執行;

通常所說的并發連接數,是指瀏覽器向服務器發起請求,建立TCP連接,每秒鐘服務器建立的總連接數,而假如,服務器處10ms能處理一個連接,那么其并發連接數就是100。

JavaScript異步機制

本節介紹JavaScript異步機制,首先來看一個例子:

for (var i = 0; i < 5; i ++) {setTimeout(function(){ console.log(i);}, 0); } console.log(i); //5 ; 5 ; 5 ; 5; 5

應該明白最后輸出的全是5:

i在此處是for循環所在上下文環境的變量,有且只有一個i; 循環結束時i==5; JavaScript單線程事件處理器在線程空閑前不會執行下一事件。

如上面第三點所述,如果要真正理解以上例子中的setTimeout(),及JavaScript異步機制,需要理解JavaScript的事件循環和并發模型。

并發模型(Concurrency model)

目前,我們已經知道,JavaScript執行異步任務時,不需要等待響應返回,可以繼續執行其他任務,而在響應返回時,會得到通知,執行回調或事件處理程序。那么這一切具體是如何完成的,又以什么規則或順序運作呢?接下來我們需要解答這個問題。

注:回調和事件處理程序本質上并無區別,只是在不同情況下,不同的叫法。

前文已經提到,JavaScript異步編程使得多個任務可以并發執行,而實現這一功能的基礎是JavScript擁有一個基于事件循環的并發模型。

堆棧與隊列

介紹JavaScript并發模型之前,先簡單介紹堆棧和隊列的區別:

堆(heap):內存中某一未被阻止的區域,通常存儲對象(引用類型); 棧(stack):后進先出的順序存儲數據結構,通常存儲函數參數和基本類型值變量(按值訪問); 隊列(queue):先進先出順序存儲數據結構。 事件循環(Event Loop)

JavaScript引擎負責解析,執行JavaScript代碼,但它并不能單獨運行,通常都得有一個宿主環境,一般如瀏覽器或Node服務器,前文說到的單線程是指在這些宿主環境創建單一線程,提供一種機制,調用JavaScript引擎完成多個JavaScript代碼塊的調度,執行(是的,JavaScript代碼都是按塊執行的),這種機制就稱為事件循環(Event Loop)。

注:這里的事件與DOM事件不要混淆,可以說這里的事件包括DOM事件,所有異步操作都是一個事件,諸如ajax請求就可以看作一個request請求事件。

JavaScript執行環境中存在的兩個結構需要了解:

消息隊列(message queue),也叫任務隊列(task queue):存儲待處理消息及對應的回調函數或事件處理程序; 執行棧(execution context stack),也可以叫執行上下文棧:JavaScript執行棧,顧名思義,是由執行上下文組成,當函數調用時,創建并插入一個執行上下文,通常稱為執行棧幀(frame),存儲著函數參數和局部變量,當該函數執行結束時,彈出該執行棧幀;

注:關于全局代碼,由于所有的代碼都是在全局上下文執行,所以執行棧頂總是全局上下文就很容易理解,直到所有代碼執行完畢,全局上下文退出執行棧,棧清空了;也即是全局上下文是第一個入棧,最后一個出棧。

任務

分析事件循環流程前,先闡述兩個概念,有助于理解事件循環:同步任務和異步任務。

任務很好理解,JavaScript代碼執行就是在完成任務,所謂任務就是一個函數或一個代碼塊,通常以功能或目的劃分,比如完成一次加法計算,完成一次ajax請求;很自然的就分為同步任務和異步任務。同步任務是連續的,阻塞的;而異步任務則是不連續,非阻塞的,包含異步事件及其回調,當我們談及執行異步任務時,通常指執行其回調函數。

事件循環流程

關于事件循環流程分解如下:

宿主環境為JavaScript創建線程時,會創建堆(heap)和棧(stack),堆內存儲JavaScript對象,棧內存儲執行上下文; 棧內執行上下文的同步任務按序執行,執行完即退棧,而當異步任務執行時,該異步任務進入等待狀態(不入棧),同時通知線程:當觸發該事件時(或該異步操作響應返回時),需向消息隊列插入一個事件消息; 當事件觸發或響應返回時,線程向消息隊列插入該事件消息(包含事件及回調); 當棧內同步任務執行完畢后,線程從消息隊列取出一個事件消息,其對應異步任務(函數)入棧,執行回調函數,如果未綁定回調,這個消息會被丟棄,執行完任務后退棧; 當線程空閑(即執行棧清空)時繼續拉取消息隊列下一輪消息(next tick,事件循環流轉一次稱為一次tick)。

使用代碼可以描述如下:

var eventLoop = []; var event; var i = eventLoop.length - 1; // 后進先出 while(eventLoop[i]) {event = eventLoop[i--]; if (event) { // 事件回調存在 event();}// 否則事件消息被丟棄 }

這里注意的一點是等待下一個事件消息的過程是同步的。

并發模型與事件循環

var ele = document.querySelector(’body’); function clickCb(event) {console.log(’clicked’); } function bindEvent(callback) {ele.addEventListener(’click’, callback); } bindEvent(clickCb);

針對如上代碼我們可以構建如下并發模型:

JavaScript異步編程

如上圖,當執行棧同步代碼塊依次執行完直到遇見異步任務時,異步任務進入等待狀態,通知線程,異步事件觸發時,往消息隊列插入一條事件消息;而當執行棧后續同步代碼執行完后,讀取消息隊列,得到一條消息,然后將該消息對應的異步任務入棧,執行回調函數;一次事件循環就完成了,也即處理了一個異步任務。

再談setTimeout(…0)

了解了JavaScript事件循環后我們再看前文關于 setTimeout(...0) 的例子就比較清晰了:

setTimeout(...0) 所表達的意思是:等待0秒后(這個時間由第二個參數值確定),往消息隊列插入一條定時器事件消息,并將其第一個參數作為回調函數;而當執行棧內同步任務執行完畢時,線程從消息隊列讀取消息,將該異步任務入棧,執行;線程空閑時再次從消息隊列讀取消息。

再看一個實例:

var start = +new Date(); var arr = []; setTimeout(function(){console.log(’time: ’ + (new Date().getTime() - start)); },10); for(var i=0;i<=1000000;i++){arr.push(i); }

執行多次輸出如下:

JavaScript異步編程

在 setTimeout 異步回調函數里我們輸出了異步任務注冊到執行的時間,發現并不等于我們指定的時間,而且兩次時間間隔也都不同,考慮以下兩點:

在讀取消息隊列的消息時,得等同步任務完成,這個是需要耗費時間的; 消息隊列先進先出原則,讀取此異步事件消息之前,可能還存在其他消息,執行也需要耗時;

所以異步執行時間不精確是必然的,所以我們有必要明白無論是同步任務還是異步任務,都不應該耗時太長,當一個消息耗時太長時,應該盡可能的將其分割成多個消息。

Web Workers

每個Web Worker或一個跨域的iframe都有各自的堆棧和消息隊列,這些不同的文檔只能通過postMessage方法進行通信,當一方監聽了message事件后,另一方才能通過該方法向其發送消息,這個message事件也是異步的,當一方接收到另一方通過postMessage方法發送來的消息后,會向自己的消息隊列插入一條消息,而后續的并發流程依然如上文所述。

JavaScript異步實現

關于JavaScript的異步實現,以前有:回調函數,發布訂閱模式,Promise三類,而在ES6中提出了生成器(Generator)方式實現,關于回調函數和發布訂閱模式實現可參見另一篇文章,后續將推出一篇詳細介紹Promise和Generator。

參考:

Concurrency model and Event Loop

來自:http://blog.codingplayboy.com/2017/04/25/js_async/

標簽: JavaScript
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产高清不卡| 91精品蜜臀一区二区三区在线 | 精品国产精品国产偷麻豆| 亚洲aⅴ网站| 综合一区在线| 日韩精品a在线观看91| 免费成人性网站| 综合激情网站| 国产麻豆一区二区三区精品视频| 国产高清日韩| 亚洲精品在线影院| 99pao成人国产永久免费视频| 99精品99| 国产色99精品9i| 亚洲伊人av| 九九久久婷婷| 亚洲精品在线a| 欧美黑人做爰爽爽爽| 色吊丝一区二区| 蜜芽一区二区三区| 国产情侣一区在线| 国产精品毛片久久| 99在线精品免费视频九九视| 日韩国产91| 免费高潮视频95在线观看网站| 久久不射网站| 国语精品一区| 性色av一区二区怡红| 国产精品久久久久久模特| 99久久精品网| 日本一区二区三区中文字幕| 精品高清久久| 久久午夜精品一区二区| 免费一级欧美片在线观看网站| 免费一二一二在线视频| 亚洲欧洲专区| 91视频久久| 免费在线欧美视频| 日韩av在线播放网址| 男人的天堂久久精品| 精品伊人久久| 久久国产精品99国产| 97精品国产| 日韩精品欧美大片| 国产99久久| 国产精品videosex极品| 亚洲中字黄色| 国产精品蜜芽在线观看| 在线观看亚洲精品福利片| 中文字幕在线看片| 欧美一级一区| 在线国产一区二区| 国产999精品在线观看| 亚洲精品进入| 99久久九九| 国产在线日韩精品| 日韩中文字幕一区二区高清99| 桃色一区二区| 国产精品大片| 亚洲精品在线二区| 欧美日韩国产高清| 黑人精品一区| 国产精品久久久久久久久久白浆| 91久久亚洲| 99久久九九| 日本欧美国产| 国产日韩亚洲欧美精品| 香蕉久久夜色精品国产| 久久国产小视频| 国产aⅴ精品一区二区四区| 7777精品| 日韩专区视频网站| 蜜臀久久99精品久久久久久9| 亚洲小说欧美另类婷婷| 欧美国产美女| 久久精品国产精品亚洲毛片| 亚洲ab电影| 蜜芽一区二区三区| 午夜一区在线| 蜜臀91精品国产高清在线观看| 中文字幕在线视频久| 黄色网一区二区| 国产欧美日韩一区二区三区四区| 免费精品视频最新在线| 99re国产精品| 狠狠爱www人成狠狠爱综合网| 久久久久久黄| 神马午夜久久| 亚洲午夜91| 欧美在线亚洲| 国产精品88久久久久久| 亚洲黑丝一区二区| 99精品在线观看| 免费不卡中文字幕在线| 亚洲午夜视频| 亚洲免费播放| 午夜欧美精品| 99久久99久久精品国产片果冰| caoporn视频在线| 91亚洲国产| 欧美日韩精品免费观看视完整| 久久久久久久久99精品大| 久久久精品日韩| 免费精品国产的网站免费观看| 国产二区精品| 国产视频一区三区| 先锋影音久久久| 欧美日韩水蜜桃| 欧美国产美女| 国产日韩一区| 亚洲精品动态| 欧美日韩亚洲国产精品| 男人的天堂久久精品| 日韩激情综合| 亚洲精品黄色| 国产精品毛片| 婷婷久久免费视频| 欧美一级一区| 黄色网一区二区| 青青久久av| 免播放器亚洲| 欧美一级全黄| 国产精品高颜值在线观看| 激情久久久久久久| 蜜桃免费网站一区二区三区| 91嫩草精品| 高清av一区| 欧美日韩尤物久久| 欧美午夜不卡影院在线观看完整版免费| 丝袜美腿亚洲一区二区图片| 奇米亚洲欧美| 亚洲黄色中文字幕| 日韩视频久久| 久久国产欧美日韩精品| 人人草在线视频| 老司机精品久久| 国产精品久久久久久久久久齐齐| 麻豆视频在线观看免费网站黄 | 日韩高清成人在线| 精品国产亚洲一区二区三区大结局 | 制服诱惑一区二区| 日本精品在线播放| 国产中文在线播放| 免费看精品久久片| 国内精品伊人| 蜜臀精品一区二区三区在线观看| 精品美女在线视频| 久久先锋影音| 国产精品毛片久久| 亚洲精品极品| 日韩专区精品| 日韩精品国产欧美| 激情亚洲影院在线观看| 视频一区日韩精品| 韩国三级一区| 欧美日韩一区二区国产| 欧美日韩一二三四| 国产精品对白久久久久粗| 精品一区三区| 久久精品色播| 最新国产精品久久久| 日韩免费小视频| 日本少妇精品亚洲第一区| 日韩不卡视频在线观看| 91精品日本| 亚洲国内精品| 欧美精品导航| 亚洲婷婷丁香| 亚洲日本网址| 国产精品久久久久久久久久妞妞 | 久久福利影视| 韩国三级一区| 麻豆传媒一区二区三区| 石原莉奈在线亚洲三区| 色婷婷久久久| 国产免费av国片精品草莓男男 | 999国产精品永久免费视频app| 国产毛片一区二区三区| 亚洲久久在线| 99视频一区| 欧美一区二区三区高清视频 | 蜜臀av性久久久久蜜臀aⅴ四虎 | 久久97视频| 91成人福利| 亚洲欧美在线专区| 婷婷久久一区| 久久精品国产68国产精品亚洲| 开心激情综合| 国产精品一区二区三区美女| 视频国产精品| 一区二区日韩免费看| 9国产精品视频| 亚洲欧洲一区二区天堂久久| 免费国产自久久久久三四区久久| 成人久久一区| 久久久亚洲一区| 99精品在线| 日韩精品1区| 国产v综合v| 久久美女性网|