91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

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

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

JavaScript單線程和異步怎么實現

發布時間:2022-02-07 09:11:07 來源:億速云 閱讀:159 作者:iii 欄目:web開發

這篇“JavaScript單線程和異步怎么實現”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“JavaScript單線程和異步怎么實現”文章吧。

JavaScript單線程和異步怎么實現

進程與線程

1. 進程:程序的一次執行, 它占有一片獨有的內存空間  ---- 可以通過windows任務管理器查看進程;

JavaScript單線程和異步怎么實現

2. 線程: 是進程內的一個獨立執行單元;是程序執行的一個完整流程;CPU的基本調度單位;

JavaScript單線程和異步怎么實現

3. 進程與線程的關系:

* 一個進程中一般至少有一個運行的線程: 主線程 -- 進程啟動后自動創建;

* 一個進程中也可以同時運行多個線程, 我們會說程序是多線程運行的;

* 一個進程內的數據可以供其中的多個線程直接共享;

* 多個進程之間的數據是不能直接共享的

4. 瀏覽器運行是單進程還是多進程?

* 有的是單進程

* firefox

* 有的是多進程

* chrome

5. 如何查看瀏覽器是否是多進程運行的呢?

* 任務管理器==>進程

JavaScript單線程和異步怎么實現

6. 瀏覽器運行是單線程還是多線程?

* 都是多線程運行的


單線程

1、什么是單線程

JavaScript語言的一大特點就是單線程,也就是說同一時間只能做一件事。

//栗子
console.log(1)
console.log(2)
console.log(3)
//輸出順序 1 2 3

2. JavaScript為什么是單線程

  • 首先是歷史原因,在創建 javascript 這門語言時,多進程、多線程的架構并不流行,硬件支持并不好。

  • 其次是因為多線程的復雜性,多線程操作需要加鎖,編碼的復雜性會增高。

  • 最后與它的用途有關,作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM,如果同時操作 DOM ,在多線程不加鎖的情況下,最終會導致 DOM 渲染的結果不可預期。

為了利用多核CPU的計算能力,HTML5提出Web Worker標準,允許JavaScript腳本創建多個線程,但是子線程完全受主線程控制,且不得操作DOM。所以,這個新標準并沒有改變JavaScript單線程的本質。


同步與異步

1、JS的 同步任務/異步任務

同步任務:主線程上排隊執行的任務,只有一個任務執行完畢,才能執行一個任務;

所有同步任務都在主線程上執行,形成一個執行棧(execution context stack)。

異步任務:主線程外執行的任務;在主線程之外還存在一個“任務隊列”(task queue),當異步任務執行完成后會以回調函數的方式放入任務隊列中等待,等主線程空閑時,主線程就會去事件隊列中取出等待的回調函數放入主線程中進行執行。這個過程反復執行就形成了js的事件循環機制(Event Loop)。

//栗子
// 同步
console.log(1)

// 異步
setTimeout(()=>{
    console.log(2)
},100)

// 同步
console.log(3)

//輸出順序 1 3 2

2、 JavaScript為什么需要異步

如果在JS代碼執行過程中,某段代碼執行過久,后面的代碼遲遲不能執行,產生阻塞(即卡死),會影響用戶體驗。

3、JavaScript怎么實現異步

1)執行棧與任務隊列

其實上面我們已經提到了,JS實現異步時通過 事件循環

我們先理解幾個概念:

  • JS任務 分為同步任務(synchronous)和異步任務(asynchronous)

  • 同步任務都在 JS引擎線程(主線程) 上執行,形成一個執行棧(call stack)

  • 事件觸發線程 管理一個 任務隊列(Task Queue)

  • 異步任務 觸發條件達成,將 回調事件 放到任務隊列(Task Queue)中

  • 執行棧中所有同步任務執行完畢,此時JS引擎線程空閑,系統會讀取任務隊列,將可運行的異步任務回調事件添加到執行棧中,開始執行

當一個JS文件第一次執行的時候,js引擎會 解析這段代碼,并將其中的同步代碼 按照執行順序加入執行棧中,然后從頭開始執行。如果當前執行的是一個方法,那么js會向執行棧中添加這個方法的執行環境,然后進入這個執行環境繼續執行其中的代碼。當這個執行環境中的代碼 執行完畢并返回結果后,js會退出這個執行環境并把這個執行環境銷毀,回到上一個方法的執行環境。這個過程反復進行,直到執行棧中的代碼全部執行完畢。

栗子

//(1)
console.log(1)

//(2)
setTimeout(()=>{
    console.log(2)
},100)

//(3)
console.log(3)
  1. 先解析整段代碼,按照順序加入到執行棧中,從頭開始執行

  2. 先執行(1),是同步的,所以直接打印 1

  3. 執行(2),發現是 setTimeout,于是調用瀏覽器的方法(webApi)執行,在 100ms后將 console.log(2) 加入到任務隊列

  4. 執行(3),同步的,直接打印 3

  5. 執行棧已經清空了,現在檢查任務隊列,(執行太快的話可能此時任務隊列還是空的,沒到100ms,還沒有將(2)的打印加到任務隊列,于是不停的檢測,直到隊列中有任務),發現有 console.log(2),于是添加到執行棧,執行console.log(2),同步代碼,直接打印 2 (如果這里是異步任務,同樣會再走一遍循環:-->任務隊列->執行棧)

所以結果是 1 3 2;

注意:setTimeout/Promise等我們稱之為任務源。而進入任務隊列的是他們指定的回調;

2)宏任務(macro task)與微任務(micro task)

上面的循環只是一個宏觀的表述,實際上異步任務之間也是有不同的,分為 宏任務(macro task) 與 微任務(micro task),最新的標準中,他們被稱為 taskjobs

  • 宏任務有哪些:script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering(渲染)

  • 微任務有哪些:process.nextTick, Promise, Object.observe(已廢棄), MutationObserver(html5新特性)

下面我們再詳細講解一下執行過程:

執行棧在執行的時候,會把宏任務放在一個宏任務的任務隊列,把微任務放在一個微任務的任務隊列,在當前執行棧為空的時候,主線程會 查看微任務隊列是否有事件存在。如果微任務隊列不存在,那么會去宏任務隊列中 取出一個任務 加入當前執行棧;如果微任務隊列存在,則會依次執行微任務隊列中的所有任務,直到微任務隊列為空(同樣,是吧隊列中的事件加到執行棧執行),然后去宏任務隊列中取出最前面的一個事件加入當前執行棧...如此反復,進入循環。

注意:

  • 宏任務和微任務的任務隊列都可以有多個

  • 當前執行棧執行完畢時會立刻先處理所有微任務隊列中的事件,然后再去宏任務隊列中取出一個事件。同一次事件循環中,微任務永遠在宏任務之前執行。

  • 不同的運行環境 循環策略可能有不同,這里探討chrome、node環境

栗子

//(1)
setTimeout(()=>{
    console.log(1)   // 宏任務
},100)

//(2)
setTimeout(()=>{
    console.log(2)  // 宏任務
},100)

//(3)
new Promise(function(resolve,reject){
    //(4)
    console.log(3)  // 直接打印
    resolve(4)
}).then(function(val){
    //(5)
    console.log(val); // 微任務
})

//(6)
new Promise(function(resolve,reject){
    //(7)
    console.log(5)   // 直接打印
    resolve(6)
}).then(function(val){
    //(8)
    console.log(val);  // 微任務
})

//(9)
console.log(7)  // 直接打印

//(10)
setTimeout(()=>{
    console.log(8) // 宏任務,單比(1)(2)宏任務早
},50)

上面的代碼在node和chrome環境的正確打印順序是 3 5 7 4 6 8 1 2

下面分析一下執行過程:

  1. 全部代碼在解析后加入執行棧

  2. 執行(1),宏任務,調用webapi setTimeout,這個方法會在100ms后將回調函數放入宏任務的任務隊列

  3. 執行(2),同(1),但是會比(1)稍后一點

  4. 執行(3),同步執行new Promise,然后執行(4),直接打印 3 ,然后resolve(4),然后.then(),把(5)放入微任務的任務隊列

  5. 執行(6),同上,先打印 5 ,再執行resolve(6),然后.then()里面的內容(8)加入到微任務的任務隊列

  6. 執行(9),同步代碼,直接打印 7

  7. 執行(10),同(1)和(2),只是時間更短,會在 50ms 后將回調 console.log(8) 加入宏任務的任務隊列

  8. 現在執行棧清空了,開始檢查微任務隊列,發現(5),加入到執行棧執行,是同步代碼,直接打印 4

  9. 任務隊列又執行完了,又檢查微任務隊列,發現(8),打印 6

  10. 任務隊列又執行完了,檢查微任務隊列,沒有任務,再檢查宏任務隊列,此時如果超過了50ms的話,會發現 console.log(8) 在宏任務隊列中,于是執行 打印 8

  11. 依次打印 1 2

注:因為渲染也是宏任務,需要在一次執行棧執行完后才會執行渲染,所以如果執行棧中同時有幾個同步的改變同一個樣式的代碼,在渲染時只會渲染最后一個。

以上就是關于“JavaScript單線程和異步怎么實現”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

向AI問一下細節

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

AI

建昌县| 赫章县| 桐柏县| 丁青县| SHOW| 会宁县| 盐池县| 灵璧县| 抚顺县| 花垣县| 专栏| 团风县| 潼关县| 巢湖市| 云南省| 乌拉特中旗| 博白县| 顺义区| 绍兴县| 柘荣县| 奉化市| 广州市| 武平县| 聊城市| 高密市| 汶川县| 大冶市| 清丰县| 读书| 秀山| 祁东县| 万荣县| 泾源县| 兴国县| 运城市| 彭州市| 卢湾区| 富源县| 新河县| 南漳县| 营山县|