成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

[Javascript] 實現(xiàn)setInterval函數(shù)

zhangwang / 520人閱讀

摘要:更方便的在于,由于自帶定時器功能,我們甚至不用自己去維護一個時間戳。請注意這里由于沒有調(diào)用另一個腳本,我們通過和的方式將我們的定時器程序傳入中。

問題

經(jīng)常使用Javascript的同學(xué)一定對setInterval非常熟悉,當(dāng)使用setInterval(callback, timer)時,每經(jīng)過timer毫秒時間,系統(tǒng)都將調(diào)用一次callback。請問全局如果沒有提供setInterval函數(shù),該如何自己實現(xiàn)這一功能?

方案一:循環(huán)或遞歸(錯誤解法)

最簡單的思路便是通過簡單的循環(huán)或者遞歸,每次檢查時間戳是否已經(jīng)超過上次觸發(fā)給定函數(shù)的時間加上間隔時間,如果已經(jīng)超過便再次觸發(fā)函數(shù),并重置計時器至當(dāng)前時間。

const setInterval1 = (func, interval) => {
    let startTime = Date.now();
    const config = { shouldStop: false };
    while (!config.shouldStop) {
        if (Date.now() - startTime >= interval) {
            func();
            startTime = Date.now();
        }
    }
    return config;
}

const myClearInterval = config => { config.shouldStop = true; }

然而這樣的解法有一個致命問題,我們將setInterval1變成一個阻塞函數(shù),主線程會卡死在這個無限循環(huán)或者遞歸中,導(dǎo)致之后的代碼或者事件無法執(zhí)行。想了解詳細原因的請戳: 并發(fā)模型與事件循環(huán),JavaScript:徹底理解同步、異步和事件循環(huán)(Event Loop)

方案二:使用setTimeout

setTimeout的好處在于,它是在消息隊列里面添加一個待執(zhí)行的消息,所以并不會堵塞主線程。更方便的在于,由于setTimeout自帶定時器功能,我們甚至不用自己去維護一個時間戳。我們可以通過不斷遞歸調(diào)用setTimeout來實現(xiàn)setInterval的效果

const setInterval2 = (func, interval) => {
    const config = { shouldStop: false }
    const loop = () => {
        if (!config.shouldStop) {
            func();
            setTimeout(loop, interval);
        }
    }
    setTimeout(loop, interval);
    return config;
}

const myClearInterval = config => { config.shouldStop = true; }
方案三:使用requestAnimationFrame

然而使用setTimeout有違這道題的初衷,因為setTimeout在本質(zhì)上和setInterval是類似的,多少有些作弊的嫌疑。那有沒有別的非阻塞方案呢?在瀏覽器環(huán)境中,我們有requestAnimationFrame(),而在nodejs環(huán)境中,我們有setImmediate()。以requestAnimationFrame為例,這將保證我們的代碼只會在每一幀render之前被遞歸一次,從而避免了阻塞其他代碼。

const setInterval3 = (func, interval) => {
    let startTime = Date.now();
    const config = { shouldStop: false }
    const check = () => {
        if (!config.shouldStop) {
            if (Date.now() - startTime > interval) {
                func();
                startTime = Date.now();
            }
            if(typeof window === "undefined") {
                setImmediate(check);
            } else {
                window.requestAnimationFrame(check)
            }
        }
    }
    check();
    return config;
}

const myClearInterval = config => { config.shouldStop = true; }
方案四:使用Web Worker

requestAnimationFrame能確保我們在每幀顯示前被調(diào)用一次,從而檢計時器是否到期,但是如果被執(zhí)行的函數(shù)計算量極大,導(dǎo)致幀內(nèi)無法完成時,該如何保證給定函數(shù)能按時執(zhí)行呢?顯然,此時只依靠主線程來確保計時程序和給定程序都能準確執(zhí)行,有點困難,但是如果將計時程序放入另一線程中,而主程序只負責(zé)監(jiān)聽定時器事件和執(zhí)行給定程序,是不是會好一些呢?所以我們這里利用瀏覽器提供的Web Worker API來實現(xiàn)多線程。請注意這里由于沒有調(diào)用另一個腳本,我們通過blob和object url的方式將我們的定時器程序check傳入Web Worker中。

const setInterval4 = (func, interval) => {
    if (typeof window !== "undefined" && window.Worker && window.Blob) {
        const check = new Blob(["(", function(){
            self.onmessage = function(e) {
              const interval = e.data;
            let startTime = Date.now();
            while(true) {
                if (Date.now() - startTime >= interval) {
                  startTime = Date.now();
                self.postMessage(Date.now());
              }
            }
          }
        }.toString(), ")()"], { type: "text/javascript" });
        const worker = new Worker(window.URL.createObjectURL(check));
        worker.onmessage = func;
        worker.postMessage(interval);
                return worker;
    } else {
        console.log("Your environment is not supported");
    }
}

const myClearInterval = config => { config.terminate() }

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/93884.html

相關(guān)文章

  • JS 異步的實現(xiàn)

    摘要:由于引擎同一時間只執(zhí)行一段代碼這是由單線程的性質(zhì)決定的,所以每個代碼塊阻塞了其它異步事件的進行。這意味著瀏覽器將等待著一個新的異步事件發(fā)生。異步的任務(wù)執(zhí)行的順序是不固定的,主要看返回的速度。 我們經(jīng)常說JS是單線程的,比如node.js研討會上大家都說JS的特色之一是單線程的,這樣使JS更簡單明了,可是大家真的理解所謂JS的單線程機制嗎?單線程時,基于事件的異步機制又該當(dāng)如何,這些知識...

    sihai 評論0 收藏0
  • javascript中,如何用setTimeout函數(shù)模擬實現(xiàn)setInterval函數(shù)?

    摘要:定義對象,用于保存映射到真實每調(diào)用一次就會自增的一個這里注意要使用局部變量保存哦,避免函數(shù)內(nèi)部直接引用,因為可能會再次變化說明使用時除了需要加上一個對象做命名空間外其實也是沒辦法哦,因為和需要共享一個叫做的映射表,其他與直接調(diào)用原生,無異舉 talk is cheap: var util = (function(){ //定義intervalObj對象,用于保存interval...

    邱勇 評論0 收藏0
  • 瀏覽器中的事件循環(huán)機制

    摘要:單線程的話,如果我們做一些的操作比如說這是一個耗時的操所那么在這將近一秒內(nèi),線程就會被阻塞,無法繼續(xù)執(zhí)行下面的任務(wù)。事件循環(huán)的主要機制就是任務(wù)隊列機制一個事件循環(huán)有一個或者多個任務(wù)隊列。 瀏覽器中的事件循環(huán)機制 網(wǎng)上一搜事件循環(huán), 很多文章標題的前面會加上 JavaScript, 但是我覺得事件循環(huán)機制跟 JavaScript 沒什么關(guān)系, JavaScript 只是一門解釋型語言, ...

    zzbo 評論0 收藏0
  • 理解javascript中的事件循環(huán)(Event Loop)

    摘要:主線程會暫時存儲等異步操作,直接向下執(zhí)行,當(dāng)某個異步事件觸發(fā)時,再通知主線程執(zhí)行相應(yīng)的回調(diào)函數(shù),通過這種機制,避免了單線程中異步操作耗時對后續(xù)任務(wù)的影響。 背景 在研究js的異步的實現(xiàn)方式的時候,發(fā)現(xiàn)了JavaScript 中的 macrotask 和 microtask 的概念。在查閱了一番資料之后,對其中的執(zhí)行機制有所了解,下面整理出來,希望可以幫助更多人。 先了解一下js的任務(wù)執(zhí)...

    mykurisu 評論0 收藏0
  • Javascript定時器那些事兒

    摘要:一什么是定時器提供了一些原生方法來實現(xiàn)延時去執(zhí)行某一段代碼,下面來簡單介紹一下設(shè)置一個定時器,在定時器到期后執(zhí)行一次函數(shù)或代碼段定時器延遲后執(zhí)行的函數(shù)延遲后執(zhí)行的代碼字符串,不推薦使用原理類似延遲的時間單位毫秒,默認值為向延遲函數(shù)傳遞而外的 一、什么是定時器 JS提供了一些原生方法來實現(xiàn)延時去執(zhí)行某一段代碼,下面來簡單介紹一下 setTimeout: 設(shè)置一個定時器,在定時器到期后執(zhí)行...

    Riddler 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<