久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      經(jīng)典技巧之JavaScript的單線程和異步

      本篇文章給大家?guī)砹岁P(guān)于JavaScript中單線程和異步的相關(guān)知識,希望對大家有幫助。

      經(jīng)典技巧之JavaScript的單線程和異步

      寫這篇文章呢,也是查閱的很多文章,但是大部分寫的都很簡單,而且概念性的東西都很模糊,于是我就找了一些課程聽了一下,做了一些筆記,在這我就簡單總結(jié)一下,方便以后復(fù)習(xí)~

      進(jìn)程與線程

      1. 進(jìn)程:程序的一次執(zhí)行, 它占有一片獨有的內(nèi)存空間 —- 可以通過windows任務(wù)管理器查看進(jìn)程;

      經(jīng)典技巧之JavaScript的單線程和異步

      2. 線程: 是進(jìn)程內(nèi)的一個獨立執(zhí)行單元;是程序執(zhí)行的一個完整流程;CPU的基本調(diào)度單位;

      經(jīng)典技巧之JavaScript的單線程和異步

      3. 進(jìn)程與線程的關(guān)系:

      * 一個進(jìn)程中一般至少有一個運行的線程: 主線程 — 進(jìn)程啟動后自動創(chuàng)建;

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

      * 一個進(jìn)程內(nèi)的數(shù)據(jù)可以供其中的多個線程直接共享;

      * 多個進(jìn)程之間的數(shù)據(jù)是不能直接共享的

      4. 瀏覽器運行是單進(jìn)程還是多進(jìn)程?

      * 有的是單進(jìn)程

      * firefox

      * 有的是多進(jìn)程

      * chrome

      5. 如何查看瀏覽器是否是多進(jìn)程運行的呢?

      * 任務(wù)管理器==>進(jìn)程

      經(jīng)典技巧之JavaScript的單線程和異步

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

      * 都是多線程運行的


      單線程

      1、什么是單線程

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

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

      2. JavaScript為什么是單線程

      • 首先是歷史原因,在創(chuàng)建 javascript 這門語言時,多進(jìn)程、多線程的架構(gòu)并不流行,硬件支持并不好。
      • 其次是因為多線程的復(fù)雜性,多線程操作需要加鎖,編碼的復(fù)雜性會增高。
      • 最后與它的用途有關(guān),作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM,如果同時操作 DOM ,在多線程不加鎖的情況下,最終會導(dǎo)致 DOM 渲染的結(jié)果不可預(yù)期。

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


      同步與異步

      1、JS的 同步任務(wù)/異步任務(wù)

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

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

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

      //栗子 // 同步 console.log(1)  // 異步 setTimeout(()=>{     console.log(2) },100)  // 同步 console.log(3)  //輸出順序 1 3 2

      2、 JavaScript為什么需要異步

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

      3、JavaScript怎么實現(xiàn)異步

      1)執(zhí)行棧與任務(wù)隊列

      其實上面我們已經(jīng)提到了,JS實現(xiàn)異步時通過 事件循環(huán)

      我們先理解幾個概念:

      • JS任務(wù) 分為同步任務(wù)(synchronous)和異步任務(wù)(asynchronous)
      • 同步任務(wù)都在 JS引擎線程(主線程) 上執(zhí)行,形成一個執(zhí)行棧(call stack)
      • 事件觸發(fā)線程 管理一個 任務(wù)隊列(Task Queue)
      • 異步任務(wù) 觸發(fā)條件達(dá)成,將 回調(diào)事件 放到任務(wù)隊列(Task Queue)中
      • 執(zhí)行棧中所有同步任務(wù)執(zhí)行完畢,此時JS引擎線程空閑,系統(tǒng)會讀取任務(wù)隊列,將可運行的異步任務(wù)回調(diào)事件添加到執(zhí)行棧中,開始執(zhí)行

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

      栗子

      //(1) console.log(1)  //(2) setTimeout(()=>{     console.log(2) },100)  //(3) console.log(3)
      1. 先解析整段代碼,按照順序加入到執(zhí)行棧中,從頭開始執(zhí)行
      2. 先執(zhí)行(1),是同步的,所以直接打印 1
      3. 執(zhí)行(2),發(fā)現(xiàn)是 setTimeout,于是調(diào)用瀏覽器的方法(webApi)執(zhí)行,在 100ms后將 console.log(2) 加入到任務(wù)隊列
      4. 執(zhí)行(3),同步的,直接打印 3
      5. 執(zhí)行棧已經(jīng)清空了,現(xiàn)在檢查任務(wù)隊列,(執(zhí)行太快的話可能此時任務(wù)隊列還是空的,沒到100ms,還沒有將(2)的打印加到任務(wù)隊列,于是不停的檢測,直到隊列中有任務(wù)),發(fā)現(xiàn)有 console.log(2),于是添加到執(zhí)行棧,執(zhí)行console.log(2),同步代碼,直接打印 2 (如果這里是異步任務(wù),同樣會再走一遍循環(huán):–>任務(wù)隊列->執(zhí)行棧)

      所以結(jié)果是 1 3 2;

      注意:setTimeout/Promise等我們稱之為任務(wù)源。而進(jìn)入任務(wù)隊列的是他們指定的回調(diào);

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

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

      • 宏任務(wù)有哪些:script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering(渲染)
      • 微任務(wù)有哪些:process.nextTick, Promise, Object.observe(已廢棄), MutationObserver(html5新特性)

      下面我們再詳細(xì)講解一下執(zhí)行過程:

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

      注意:

      • 宏任務(wù)和微任務(wù)的任務(wù)隊列都可以有多個
      • 當(dāng)前執(zhí)行棧執(zhí)行完畢時會立刻先處理所有微任務(wù)隊列中的事件,然后再去宏任務(wù)隊列中取出一個事件。同一次事件循環(huán)中,微任務(wù)永遠(yuǎn)在宏任務(wù)之前執(zhí)行。
      • 不同的運行環(huán)境 循環(huán)策略可能有不同,這里探討chrome、node環(huán)境

      栗子

      //(1) setTimeout(()=>{     console.log(1)   // 宏任務(wù) },100)  //(2) setTimeout(()=>{     console.log(2)  // 宏任務(wù) },100)  //(3) new Promise(function(resolve,reject){     //(4)     console.log(3)  // 直接打印     resolve(4) }).then(function(val){     //(5)     console.log(val); // 微任務(wù) })  //(6) new Promise(function(resolve,reject){     //(7)     console.log(5)   // 直接打印     resolve(6) }).then(function(val){     //(8)     console.log(val);  // 微任務(wù) })  //(9) console.log(7)  // 直接打印  //(10) setTimeout(()=>{     console.log(8) // 宏任務(wù),單比(1)(2)宏任務(wù)早 },50)

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

      下面分析一下執(zhí)行過程:

      1. 全部代碼在解析后加入執(zhí)行棧
      2. 執(zhí)行(1),宏任務(wù),調(diào)用webapi setTimeout,這個方法會在100ms后將回調(diào)函數(shù)放入宏任務(wù)的任務(wù)隊列
      3. 執(zhí)行(2),同(1),但是會比(1)稍后一點
      4. 執(zhí)行(3),同步執(zhí)行new Promise,然后執(zhí)行(4),直接打印 3 ,然后resolve(4),然后.then(),把(5)放入微任務(wù)的任務(wù)隊列
      5. 執(zhí)行(6),同上,先打印 5 ,再執(zhí)行resolve(6),然后.then()里面的內(nèi)容(8)加入到微任務(wù)的任務(wù)隊列
      6. 執(zhí)行(9),同步代碼,直接打印 7
      7. 執(zhí)行(10),同(1)和(2),只是時間更短,會在 50ms 后將回調(diào) console.log(8) 加入宏任務(wù)的任務(wù)隊列
      8. 現(xiàn)在執(zhí)行棧清空了,開始檢查微任務(wù)隊列,發(fā)現(xiàn)(5),加入到執(zhí)行棧執(zhí)行,是同步代碼,直接打印 4
      9. 任務(wù)隊列又執(zhí)行完了,又檢查微任務(wù)隊列,發(fā)現(xiàn)(8),打印 6
      10. 任務(wù)隊列又執(zhí)行完了,檢查微任務(wù)隊列,沒有任務(wù),再檢查宏任務(wù)隊列,此時如果超過了50ms的話,會發(fā)現(xiàn) console.log(8) 在宏任務(wù)隊列中,于是執(zhí)行 打印 8
      11. 依次打印 1 2

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

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號