成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

zhangwang / 474人閱讀

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

問題

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

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

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

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; }

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

方案二:使用setTimeout

setTimeout的好處在于,它是在消息隊(duì)列里面添加一個(gè)待執(zhí)行的消息,所以并不會(huì)堵塞主線程。更方便的在于,由于setTimeout自帶定時(shí)器功能,我們甚至不用自己去維護(hù)一個(gè)時(shí)間戳。我們可以通過不斷遞歸調(diào)用setTimeout來實(shí)現(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有違這道題的初衷,因?yàn)?b>setTimeout在本質(zhì)上和setInterval是類似的,多少有些作弊的嫌疑。那有沒有別的非阻塞方案呢?在瀏覽器環(huán)境中,我們有requestAnimationFrame(),而在nodejs環(huán)境中,我們有setImmediate()。以requestAnimationFrame為例,這將保證我們的代碼只會(huì)在每一幀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能確保我們?cè)诿繋@示前被調(diào)用一次,從而檢計(jì)時(shí)器是否到期,但是如果被執(zhí)行的函數(shù)計(jì)算量極大,導(dǎo)致幀內(nèi)無法完成時(shí),該如何保證給定函數(shù)能按時(shí)執(zhí)行呢?顯然,此時(shí)只依靠主線程來確保計(jì)時(shí)程序和給定程序都能準(zhǔn)確執(zhí)行,有點(diǎn)困難,但是如果將計(jì)時(shí)程序放入另一線程中,而主程序只負(fù)責(zé)監(jiān)聽定時(shí)器事件和執(zhí)行給定程序,是不是會(huì)好一些呢?所以我們這里利用瀏覽器提供的Web Worker API來實(shí)現(xiàn)多線程。請(qǐng)注意這里由于沒有調(diào)用另一個(gè)腳本,我們通過blob和object url的方式將我們的定時(shí)器程序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)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/93884.html

相關(guān)文章

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

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

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

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

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

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

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

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

    mykurisu 評(píng)論0 收藏0
  • Javascript定時(shí)器那些事兒

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

    Riddler 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<