<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        如何通過setTimeout理解JS運行機制詳解

        來源:懂視網(wǎng) 責編:小采 時間:2020-11-27 21:59:54
        文檔

        如何通過setTimeout理解JS運行機制詳解

        如何通過setTimeout理解JS運行機制詳解:序 setTimeout()函數(shù):用來指定某個函數(shù)或某段代碼在多少毫秒之后執(zhí)行。它返回一個整數(shù),表示定時器timer的編號,可以用來取消該定時器。 例子 console.log(1); setTimeout(function () { console.log(2); }, 0); consol
        推薦度:
        導讀如何通過setTimeout理解JS運行機制詳解:序 setTimeout()函數(shù):用來指定某個函數(shù)或某段代碼在多少毫秒之后執(zhí)行。它返回一個整數(shù),表示定時器timer的編號,可以用來取消該定時器。 例子 console.log(1); setTimeout(function () { console.log(2); }, 0); consol

        任務隊列

        那么單線程的JavasScript是怎么實現(xiàn)“非阻塞執(zhí)行”呢?

        答:異步容易實現(xiàn)非阻塞,所以在JavaScript中對于耗時的操作或者時間不確定的操作,使用異步就成了必然的選擇。
        諸如事件點擊觸發(fā)回調函數(shù)、ajax通信、計時器這種異步處理是如何實現(xiàn)的呢?

        答:任務隊列

        所有任務可以分成兩種,一種是同步任務(synchronous),另一種是異步任務(asynchronous)。

        任務隊列:一個先進先出的隊列,它里面存放著各種事件和任務。

        同步任務

        同步任務:在主線程上排隊執(zhí)行的任務,只有前一個任務執(zhí)行完畢,才能執(zhí)行后一個任務。

      1. 輸出
      2. 如:console.log()
      3. 變量的聲明
      4. 同步函數(shù):如果在函數(shù)返回的時候,調用者就能夠拿到預期的返回值或者看到預期的效果,那么這個函數(shù)就是同步的。
      5. 異步任務

      6. setTimeout和setInterval
      7. DOM事件
      8. Promise
      9. process.nextTick
      10. fs.readFile
      11. http.get
      12. 異步函數(shù):如果在函數(shù)返回的時候,調用者還不能夠得到預期結果,而是需要在將來通過一定的手段得到,那么這個函數(shù)就是異步的。
      13. 除此之外,任務隊列又分為macro-task(宏任務)與micro-task(微任務),在ES5標準中,它們被分別稱為task與job。

        宏任務

        1. I/O
        2. setTimeout
        3. setInterval
        4. setImmdiate
        5. requestAnimationFrame

        微任務

        1. process.nextTick
        2. Promise
        3. Promise.then
        4. MutationObserver

        宏任務和微任務的執(zhí)行順序

        一次事件循環(huán)中,先執(zhí)行宏任務隊列里的一個任務,再把微任務隊列里的所有任務執(zhí)行完畢,再去宏任務隊列取下一個宏任務執(zhí)行。

        注:在當前的微任務沒有執(zhí)行完成時,是不會執(zhí)行下一個宏任務的。

        三、setTimeout運行機制

        setTimeout 和 setInterval的運行機制是將指定的代碼移出本次執(zhí)行,等到下一輪 Event Loop 時,再檢查是否到了指定時間。如果到了,就執(zhí)行對應的代碼;如果不到,就等到再下一輪 Event Loop 時重新判斷。

        這意味著,setTimeout指定的代碼,必須等到本次執(zhí)行的所有同步代碼都執(zhí)行完,才會執(zhí)行。

        優(yōu)先關系:異步任務要掛起,先執(zhí)行同步任務,同步任務執(zhí)行完畢才會響應異步任務。

        四、進階

        console.log('A');
        setTimeout(function () {
         console.log('B');
        }, 0);
        while (1) {}

        大家再猜一下這段程序輸出的結果會是什么?

        答:A

        注:建議先注釋掉while循環(huán)代碼塊的代碼,執(zhí)行后強制刪除進程,不然會造成“假死”。

        同步隊列輸出A之后,陷入while(true){}的死循環(huán)中,異步任務不會被執(zhí)行。

        類似的,有時addEventListener()方法監(jiān)聽點擊事件click,用戶點了某個按鈕會卡死,就是因為當前JS正在處理同步隊列,無法將click觸發(fā)事件放入執(zhí)行棧,不會執(zhí)行,出現(xiàn)“假死”。

        五、定時獲取接口更新數(shù)據(jù)

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

        輸出結果為,隔1s后一起輸出:4 4 4 4

        for循環(huán)是一個同步任務,為什么連續(xù)輸出四個4?

        答:因為有隊列插入的時間,即使執(zhí)行時間從1000改成0,還是輸出四個4。

        那么這個問題是如何產(chǎn)生和解決的呢?請接著閱讀

        異步隊列執(zhí)行的時間

        執(zhí)行到異步任務的時候,會直接放到異步隊列中嗎?

        答案是不一定的。

        因為瀏覽器有個定時器(timer)模塊,定時器到了執(zhí)行時間才會把異步任務放到異步隊列。
        for循環(huán)體執(zhí)行的過程中并沒有把setTimeout放到異步隊列中,只是交給定時器模塊了。4個循環(huán)體執(zhí)行速度非常快(不到1毫秒)。定時器到了設置的時間才會把setTimeout語句放到異步隊列中。

        即使setTimeout設置的執(zhí)行時間為0毫秒,也按4毫秒算。

        這就解釋了上題為什么會連續(xù)輸出四個4的原因。

        HTML5 標準規(guī)定了setTimeout()的第二個參數(shù)的最小值,即最短間隔,不得低于4毫秒。如果低于這個值,就會自動增加。在此之前,老版本的瀏覽器都將最短間隔設為10毫秒。

        利用閉包實現(xiàn) setTimeout 間歇調用

        for (let i = 0; i < 4; i++) {
         (function (j) {
         setTimeout(function () {
         console.log(j);
         }, 1000 * i)
         })(i);
        }

        執(zhí)行后,會隔1s輸出一個值,分別是:0 1 2 3

      14. 此方法巧妙利用IIFE聲明即執(zhí)行的函數(shù)表達式來解決閉包造成的問題。
      15. 將var改為let,使用了ES6語法。
      16. 這里也可以用setInterval()方法來實現(xiàn)間歇調用。

        詳見:setTimeout和setInterval的區(qū)別

        利用JS中基本類型的參數(shù)傳遞是按值傳遞的特征實現(xiàn)

        var output = function (i) {
         setTimeout(function () {
         console.log(i);
        
         }, 1000 * i)
        }
        for (let i = 0; i < 4; i++) {
         output(i);
        }

        執(zhí)行后,會隔1s輸出一個值,分別是:0 1 2 3

        實現(xiàn)原理:傳過去的i值被復制了。

        基于Promise的解決方案

        const tasks = [];
        
        const output = (i) => new Promise((resolve) => {
         setTimeout(() => {
         console.log(i);
         resolve();
         }, 1000 * i);
        
        });
        
        //生成全部的異步操作
        for (var i = 0; i < 5; i++) {
         tasks.push(output(i));
        }
        //同步操作完成后,
        輸出最后的i Promise.all(tasks).then(() => { setTimeout(() => { console.log(i); }, 1000) })

        執(zhí)行后,會隔1s輸出一個值,分別是:0 1 2 3 4 5

        優(yōu)點:提高了代碼的可讀性。

        注意:如果沒有處理Promise的reject,會導致錯誤被丟進黑洞。

        使用ES7中的async await特性的解決方案(推薦)

        const sleep = (timeountMS) => new Promise((resolve) => {
         setTimeout(resolve, timeountMS);
        });
        
        (async () => { //聲明即執(zhí)行的async
         for (var i = 0; i < 5; i++) {
         await sleep(1000);
         console.log(i);
         }
        
         await sleep(1000);
         console.log(i);
        
        })();

        執(zhí)行后,會隔1s輸出一個值,分別是:0 1 2 3 4 5

        六、事件循環(huán) Event Loop


        主線程從任務隊列中讀取事件,這個過程是循環(huán)不斷的,所以整個的這種運行機制又稱為Event Loop。

        有時候 setTimeout明明寫的延時3秒,實際卻5,6秒才執(zhí)行函數(shù),這又是因為什么?

        答:setTimeout 并不能保證執(zhí)行的時間,是否及時執(zhí)行取決于 JavaScript 線程是擁擠還是空閑。

        瀏覽器的JS引擎遇到setTimeout,拿走之后不會立即放入異步隊列,同步任務執(zhí)行之后,timer模塊會到設置時間之后放到異步隊列中。js引擎發(fā)現(xiàn)同步隊列中沒有要執(zhí)行的東西了,即運行棧空了就從異步隊列中讀取,然后放到運行棧中執(zhí)行。所以setTimeout可能會多了等待線程的時間。

        這時setTimeout函數(shù)體就變成了運行棧中的執(zhí)行任務,運行棧空了,再監(jiān)聽異步隊列中有沒有要執(zhí)行的任務,如果有就繼續(xù)執(zhí)行,如此循環(huán),就叫Event Loop。

        七、總結

        JavaScript通過事件循環(huán)和瀏覽器各線程協(xié)調共同實現(xiàn)異步。同步可以保證順序一致,但是容易導致阻塞;異步可以解決阻塞問題,但是會改變順序性。

        知識點梳理:

      17. 理解JS的單線程的概念:一段時間內(nèi)做一件事
      18. 理解任務隊列:同步任務、異步任務
      19. 理解 Event Loop
      20. 理解哪些語句會放入異步任務隊列
      21. 理解語句放入異步任務隊列的時機
      22. 最后,希望大家閱后有所收獲。🤠

        好了,

        聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        如何通過setTimeout理解JS運行機制詳解

        如何通過setTimeout理解JS運行機制詳解:序 setTimeout()函數(shù):用來指定某個函數(shù)或某段代碼在多少毫秒之后執(zhí)行。它返回一個整數(shù),表示定時器timer的編號,可以用來取消該定時器。 例子 console.log(1); setTimeout(function () { console.log(2); }, 0); consol
        推薦度:
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 91九色精品国产免费| 免费无码黄网站在线观看| 亚洲国产精品自产在线播放| 久久亚洲AV成人无码国产最大| 久久久久久久91精品免费观看| 亚洲成av人片在线看片| 4399好看日本在线电影免费| 亚洲综合色区中文字幕| 日韩在线视频免费| 久久久久亚洲AV综合波多野结衣 | 免费观看的av毛片的网站| 亚洲一区二区三区成人网站| 好吊妞在线成人免费| 国产91成人精品亚洲精品| 亚洲国产成人精品女人久久久 | 国产亚洲AV手机在线观看| 免费播放在线日本感人片| 亚洲国产第一页www| 国产在线a免费观看| 亚洲AV无码精品国产成人| 久久久久亚洲精品男人的天堂| 97人妻精品全国免费视频| 亚洲天堂一区在线| 国产极品粉嫩泬免费观看| 中文字幕在线成人免费看| 亚洲精品456在线播放| 国产成人免费一区二区三区| 97在线免费视频| 亚洲国产成人久久| 亚洲精品老司机在线观看| 日本一道本不卡免费 | 男男gay做爽爽免费视频| 亚洲国产无套无码av电影| 四虎在线视频免费观看视频| 亚洲AV综合色区无码另类小说| 一级白嫩美女毛片免费| 少妇中文字幕乱码亚洲影视| 成人a视频片在线观看免费| 久久久久女教师免费一区| 亚洲一区二区三区四区视频 | 日本一卡精品视频免费|