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

資訊專欄INFORMATION COLUMN

process.nextTick() 、setTimeout()、setInterval() 運(yùn)行機(jī)

lscho / 3399人閱讀

摘要:注意如果主邏輯的代碼執(zhí)行時(shí)間已經(jīng)超過了第二個(gè)參數(shù)設(shè)置的時(shí)間,那么等運(yùn)行到該回調(diào)函數(shù)時(shí),它會(huì)忽略掉這個(gè)時(shí)間,并立即執(zhí)行。如果某一個(gè)進(jìn)行大量的計(jì)算,那么它就會(huì)阻塞在當(dāng)前的回調(diào)函數(shù)中,等待該計(jì)算完成后,再執(zhí)行下一個(gè)的回調(diào)函數(shù)。

setTimeout()

? JavaScript是一個(gè)單線程的語(yǔ)言,也就是說它同一時(shí)間只能執(zhí)行一段代碼,接下來我們通過兩個(gè)例子說明一下單線程語(yǔ)言和多線程語(yǔ)言的區(qū)別。
setTimeout 代碼單線程運(yùn)行機(jī)制:

/**
 * setTimeout 執(zhí)行是要等主線線程的流程執(zhí)行完畢之后才會(huì)進(jìn)行,并且按照setTimeout設(shè)置的順序進(jìn)行排隊(duì)執(zhí)行。
 * 如果某一個(gè)setTimeout進(jìn)行大量的計(jì)算,那么它就會(huì)阻塞在當(dāng)前的setTimeout回調(diào)函數(shù)中,等待該計(jì)算完成后,再執(zhí)行下一個(gè)setTimeout的回調(diào)函數(shù)。
 */

setTimeout(() => {
    console.log("setTimeout - a");
},0);
console.log(1);
console.log(2);
setTimeout(() => {
    for (let i = 0; i < 10000022200; i++){}
    console.log("setTimeout - b");
},0);
console.log(3);
setTimeout(() => {
    console.log("setTimeout - c");
},0);
console.log(4);
setTimeout(() => {
    console.log("setTimeout - d");
},0);
console.log(5);

for (let i = 0; i < 10000222200; i++) {}        //一直等待它執(zhí)行完畢后,才會(huì)執(zhí)行setTimeout的回調(diào)。

? 從運(yùn)行結(jié)果上可以看出,雖然setTimeout - a 是寫在代碼當(dāng)最開頭,延時(shí)時(shí)間也為0,但是,它并沒有立即執(zhí)行;而是等主邏輯的代碼執(zhí)行完畢后才進(jìn)行調(diào)用的,當(dāng)代碼運(yùn)行到25行的時(shí)候,由于這里有一個(gè)長(zhǎng)長(zhǎng)的循環(huán),所以這里會(huì)阻塞等待一段時(shí)間,才會(huì)運(yùn)行到第一個(gè)setTimeout。setTimeout的運(yùn)行順序是根據(jù)你代碼中編寫的順序和延時(shí)時(shí)間決定的,下面通過一張圖來說明上述代碼的運(yùn)行機(jī)制:

? 從運(yùn)行結(jié)果中,可以看出如果主邏輯代碼沒有執(zhí)行完畢,setTimeout的回調(diào)函數(shù)是永遠(yuǎn)不會(huì)觸發(fā)的,這就是單線程,它同一時(shí)間只能做一件事。

? **注意:如果主邏輯的代碼執(zhí)行時(shí)間已經(jīng)超過了setTimeout第二個(gè)參數(shù)設(shè)置的timeout時(shí)間,那么等運(yùn)行到該回調(diào)函數(shù)時(shí),它會(huì)忽略掉這個(gè)時(shí)間,并立即執(zhí)行。下面通過一段代碼進(jìn)行驗(yàn)證:

/**
 * setTimeout 執(zhí)行是要等主線線程的流程執(zhí)行完畢之后才會(huì)進(jìn)行,并且按照setTimeout設(shè)置的順序進(jìn)行排隊(duì)執(zhí)行。
 * 如果某一個(gè)setTimeout進(jìn)行大量的計(jì)算,那么它就會(huì)阻塞在當(dāng)前的setTimeout回調(diào)函數(shù)中,等待該計(jì)算完成后,再執(zhí)行下一個(gè)setTimeout的回調(diào)函數(shù)。
 *
 * 執(zhí)行順序:即使setTimeout放在最前面執(zhí)行,它也是等到主線程執(zhí)行完畢后,才運(yùn)行,這就是單線程運(yùn)行機(jī)制。
 * setTimeout中的第二個(gè)參數(shù)timeout這個(gè)延時(shí)時(shí)間,是一個(gè)相對(duì)時(shí)間,如果主線程運(yùn)行的時(shí)間,已經(jīng)超過了這個(gè)時(shí)間,那么執(zhí)行到這個(gè)setTimeout的時(shí)候,會(huì)忽略這個(gè)時(shí)間,直接調(diào)用函數(shù)。
 */

setTimeout(() => {
    console.log("setTimeout - a");
},0);
setTimeout(() => {
    for (let i = 0; i < 10000022200; i++){}
    console.log("setTimeout - b");
},0);
setTimeout(() => {
    console.log("setTimeout - c");
},0);
setTimeout(() => {
    console.log("setTimeout - d");
},10000);

console.log(1);
console.log(2);
console.log(3);
console.log(4);
console.log(5);

for (let i = 0; i < 10000222200; i++) {}        //一直等待它執(zhí)行完畢后,才會(huì)執(zhí)行setTimeout的回調(diào)。

從上述運(yùn)行結(jié)果可以看出,即使setTimeout放在主邏輯到最前邊,但是它依然是要等到主邏輯到代碼完全執(zhí)行完畢后才執(zhí)行。

由于29行有大量的循環(huán)邏輯,主邏輯大概會(huì)阻塞20秒鐘左右,所以當(dāng)調(diào)用到19行的setTimeout的回調(diào)函數(shù)時(shí),會(huì)忽略掉它設(shè)置timeout參數(shù),并立即執(zhí)行該回調(diào)函數(shù)。

下面我們通過一段Java的代碼演示一下多線程,以此說明一下單線程與多線程的區(qū)別:

Java多線程代碼運(yùn)行機(jī)制:

public class Main {
    public static void main(String[] args) {
        // 控制臺(tái)打印輸出
        System.out.println("1");
        // 啟動(dòng)一個(gè)線程
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("線程1 before");
                for(int i = 0; i < 2099222220L; i++) {}
                System.out.println("線程1 after");
            }
        }).start();
        // 控制臺(tái)打印輸出
        System.out.println("2");
        // 啟動(dòng)一個(gè)線程
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("線程2");
            }
        }).start();
        // 控制臺(tái)打印輸出
        System.out.println("3");
        // 通過一個(gè)大的循環(huán)阻塞主線程一段時(shí)間,看看會(huì)不會(huì)影響線程的運(yùn)行
        for(int i = 0; i < 2099222220L; i++) {}
        // 控制臺(tái)打印輸出
        System.out.println("4");
    }
}

從運(yùn)行結(jié)果上可以看出,多線程的語(yǔ)言,主線程與子線程之間是完全相互獨(dú)立的,即使主線程中存在大量的計(jì)算邏輯,也不會(huì)阻塞子線程的運(yùn)行;子線程之間也是相互獨(dú)立的,例如:線程1中存在大量計(jì)算邏輯并不會(huì)影響線程2的正在執(zhí)行。

Java默認(rèn)的子線程執(zhí)行順序是由cpu隨機(jī)調(diào)度的,上述的線程1啟動(dòng)后,cpu就沒有馬上調(diào)度到它。

process.nextTick()

? process.nextTick() 是Node.js提供的一個(gè)異步執(zhí)行函數(shù),它不是setTimeout(fn, 0)的別名,它的效率更高,它的執(zhí)行順序要早于setTimeout和setInterval,它是在主邏輯的末尾任務(wù)隊(duì)列調(diào)用之前執(zhí)行。下面通過一段代碼進(jìn)行驗(yàn)證:

/**
 * 執(zhí)行順序:主線程邏輯 => nextTick => setTimeout
 *
 */
console.log(1);
setTimeout(() => console.log("setTimeout=> 1"),0);
process.nextTick(() => console.log("nextTick=> 1"));
console.log(2);
setTimeout(() => console.log("setTimeout=> 2"),0);
process.nextTick(() => {
    console.log("nextTick=> 2");
    for (let i = 0; i < 10000222200; i++) {}    //一直等待它執(zhí)行完畢后,才會(huì)執(zhí)行下一個(gè)nextTick()和之后的任務(wù)隊(duì)列中的回調(diào)函數(shù)
});
console.log(3);
process.nextTick(() => console.log("nextTick=> 3"));
setTimeout(() => console.log("setTimeout=> 3"),0);
console.log(4);
setTimeout(() => console.log("setTimeout=> 4"),0);
process.nextTick(() => console.log("nextTick=> 4"));
console.log(5);

for (let i = 0; i < 10000222200; i++) {}        //一直等待它執(zhí)行完畢后,才會(huì)執(zhí)行nextTick和setTimeout的回調(diào)。

從運(yùn)行結(jié)果中我們可以發(fā)現(xiàn),即使setTimeout設(shè)置的時(shí)機(jī)要早于process.nextTick(),但是process.nextTick()的執(zhí)行時(shí)機(jī)還是要早于setTimeout,這就證明是了process.nextTick() 的執(zhí)行時(shí)機(jī)是在任務(wù)隊(duì)列調(diào)用之前進(jìn)行執(zhí)行的。

setInterval()

? setInterval() 是一個(gè)定時(shí)器函數(shù),可按照指定的周期(以毫秒計(jì))來不斷調(diào)用函數(shù)或計(jì)算表達(dá)式。但是由于JavaScript是一個(gè)單線程的語(yǔ)言,所以這個(gè)定時(shí)器的指定的周期回調(diào)時(shí)間,并不準(zhǔn)確;下面通過一段代碼來說明一下:

/**
 * setInterval 也是要等待主線程執(zhí)行完畢后,才會(huì)進(jìn)行調(diào)用, 如果timeout時(shí)間一樣,就按照setInterval設(shè)置的順序進(jìn)行執(zhí)行。
 * 如果有一個(gè)setInterval回調(diào)函數(shù)中有大量的計(jì)算,那么線程就阻塞在這個(gè)回調(diào)函數(shù)里,其他的setInterval也會(huì)等到這個(gè)回調(diào)執(zhí)行完畢后才會(huì)調(diào)用。
 */

console.log("main => 1");
setInterval(() => {
    console.log("setInterval=> 2 before");
    for (let i = 0; i < 10022222220; i++) {}    // 此處會(huì)阻塞一段時(shí)間,等待計(jì)算完畢后才會(huì)執(zhí)行下一個(gè)setInterval的回調(diào)。
    console.log("setInterval=> 2 after");
}, 1000);
setInterval(() => {
    console.log("setInterval=> 1");
}, 1000);
console.log("main => 2");

for (let i = 0; i < 1002222200; i++) {}     // 此處主邏輯會(huì)阻塞一段時(shí)間進(jìn)行循環(huán)計(jì)算,只有主邏輯代碼執(zhí)行完畢后才會(huì)調(diào)用setInterval

? 上述代碼中同時(shí)啟動(dòng)了兩個(gè)setInterval() 并且它們的回調(diào)周期時(shí)間都為1000毫秒, 但是從運(yùn)行結(jié)果中我們可以發(fā)現(xiàn)這倆setInterval()的回調(diào)周期時(shí)間遠(yuǎn)遠(yuǎn)超出了1000毫秒;造成這種情況的主要有兩個(gè)地方:

? 第一是在代碼的第17行,這里有一個(gè)很大的循環(huán)計(jì)算,它的循環(huán)時(shí)間遠(yuǎn)遠(yuǎn)超過了1000毫秒,所以這倆setInterval只能等主邏輯的代碼執(zhí)行完畢后才能執(zhí)行。

? 第二是在代碼的第9行,在第一個(gè)setInterval里也有一個(gè)很大的循環(huán)計(jì)算,它的循環(huán)時(shí)間也超過了1000毫秒,所以第二個(gè)setInterval的回調(diào)函數(shù)也必須要等待前一個(gè)setInterval執(zhí)行完畢后才能進(jìn)行調(diào)用。

? 由此我們可以得出一個(gè)結(jié)論:setInterval()的執(zhí)行時(shí)機(jī)是在主邏輯執(zhí)行完畢之后,它的執(zhí)行順序是根據(jù)回調(diào)周期的時(shí)間和設(shè)置的順序進(jìn)行調(diào)用,同一時(shí)間只會(huì)執(zhí)行一個(gè)setInterval的回調(diào)函數(shù),只有等待上一個(gè)setInterval回調(diào)函數(shù)執(zhí)行完畢后,才能執(zhí)行下一個(gè)setInterval的回調(diào)函數(shù)。

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

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

相關(guān)文章

  • js 執(zhí)行機(jī)制 事件循環(huán)

    摘要:事件完成,回調(diào)函數(shù)進(jìn)入。我們來分析一段較復(fù)雜的代碼,看看你是否真的掌握了的執(zhí)行機(jī)制第一輪事件循環(huán)流程分析如下整體作為第一個(gè)宏任務(wù)進(jìn)入主線程,遇到,輸出。宏任務(wù)微任務(wù)第三輪事件循環(huán)宏任務(wù)執(zhí)行結(jié)束,執(zhí)行兩個(gè)微任務(wù)和。 關(guān)于JavaScript 首先js是單線程的,執(zhí)行任務(wù)肯定是一個(gè)接著一個(gè)。在最新的html5中提出了web-worker,但是JavaScript是單線程這一核心沒有改變,一...

    JackJiang 評(píng)論0 收藏0
  • 筆試題之Event Loop終極篇

    摘要:下面開始分析開頭的代碼第一輪事件循環(huán)流程整體作為第一個(gè)宏任務(wù)進(jìn)入主線程,遇到,輸出遇到函數(shù)聲明,聲明暫時(shí)不用管遇到,其回調(diào)函數(shù)被分發(fā)到微任務(wù)中。我們記為遇到,其回調(diào)函數(shù)被分發(fā)到宏任務(wù)中。 先上一道常見的筆試題 console.log(1); async function async1() { console.log(2); await async2(); con...

    niceforbear 評(píng)論0 收藏0
  • 面試題之Event Loop終極篇

    摘要:下面開始分析開頭的代碼第一輪事件循環(huán)流程整體作為第一個(gè)宏任務(wù)進(jìn)入主線程,遇到,輸出遇到函數(shù)聲明,聲明暫時(shí)不用管遇到,其回調(diào)函數(shù)被分發(fā)到微任務(wù)中。我們記為遇到,其回調(diào)函數(shù)被分發(fā)到宏任務(wù)中。 先上一道常見的筆試題 console.log(1); async function async1() { console.log(2); await async2(); con...

    233jl 評(píng)論0 收藏0
  • 徹底弄懂 JavaScript 執(zhí)行機(jī)

    摘要:關(guān)于這部分有嚴(yán)格的文字定義,但本文的目的是用最小的學(xué)習(xí)成本徹底弄懂執(zhí)行機(jī)制,所以同步和異步任務(wù)分別進(jìn)入不同的執(zhí)行場(chǎng)所,同步的進(jìn)入主線程,異步的進(jìn)入并注冊(cè)函數(shù)。宏任務(wù)微任務(wù)第三輪事件循環(huán)宏任務(wù)執(zhí)行結(jié)束,執(zhí)行兩個(gè)微任務(wù)和。 不論你是javascript新手還是老鳥,不論是面試求職,還是日常開發(fā)工作,我們經(jīng)常會(huì)遇到這樣的情況:給定的幾行代碼,我們需要知道其輸出內(nèi)容和順序。 因?yàn)閖avascr...

    gyl_coder 評(píng)論0 收藏0
  • 徹底搞懂JavaScript執(zhí)行機(jī)

    摘要:徹底搞懂執(zhí)行機(jī)制首先我們大家都了解的是,是一門單線程語(yǔ)言,所以我們就可以得出是按照語(yǔ)句順序執(zhí)行的首先看這個(gè)顯然大家都知道結(jié)果,依次輸出,然而換一種這個(gè)時(shí)候再看代碼的順序執(zhí)行,輸出,,,。不過即使主線程為空,也是達(dá)不到的,根據(jù)標(biāo)準(zhǔn),最低是。 徹底搞懂JavaScript執(zhí)行機(jī)制 首先我們大家都了解的是,JavaScript 是一門單線程語(yǔ)言,所以我們就可以得出: JavaScript 是...

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

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

0條評(píng)論

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