浅谈Event Loop再给你安排7个实例

207 阅读1分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路

如想深入了解请参考:

juejin.cn/post/684490…

juejin.cn/post/707712…

JS单线程

在 JavaScript 中我们听到最多的词可能就是所谓的“单线程”,所以导致了在 JS 中所谓的异步并行模型和许多后台语言是不同的。简而言之,虽然 JavaScript 是在单线程中去执行所有的操作,但它会基于事件循环(EventLoop)的过程去实现所谓的“异步”,从而给我们造成多线程的感觉。

Event Loop

JavaScript中,任务被分为两种,一种宏任务(MacroTask)也叫Task,一种叫微任务(MicroTask

宏任务

script全部代码、setTimeoutsetIntervalsetImmediate

微任务

Process.nextTick(Node独有)Promise

浏览器中的Event Loop

Javascript 有一个 main thread 主线程和 call-stack 调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。

JS调用栈

JS调用栈采用的是后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。

同步任务和异步任务

Javascript单线程任务被分为同步任务异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。

16860ae5ad02f993_tplv-t2oaga2asx-zoom-in-crop-mark_1304_0_0_0.awebp

事例

实例1

<body>
    <script>
        //ES6新增了promise对象,那任务就不能简单的分为同步任务和异步任务了. 
        //那要如何划分: 
        //同步任务:
        //宏任务: script标签 计时器 事件 ajax请求(axios本质)
        //微任务: then await

        //事件循环: 
        //1.进入到script标签,就进入到了第一次事件循环. 
        //2.找到同步任务
        //3.找到宏任务,放入到宏任务队列里.
        //4.找到微任务,放入到微任务队列里.
        //5.先执行完这一次事件循环的所有同步任务,再依次的去执行微任务,微任务队列清空了就表示这一次事件循环结束了. 
        //6.去宏任务队列中找一个任务出来.进入到第二次事件循环
        //... ..... ......
        //依次反复知道清空宏任务队列,那就结束了.

        console.log(1);

        setTimeout(() => {
            console.log(2);
            new Promise((resolve, reject) => {
                console.log(3);
                resolve();
                console.log(4)
            }).then(res => {
                console.log(5);
            })
            console.log(6)
        }, 0)

        console.log(7);
        
        new Promise((resolve, reject) => {
            console.log(8);
            resolve();
            console.log(9)
        }).then(res => {
            console.log(10);
        })
    </script>
</body>

实例2

<body>
    <script>
        console.log(1)
        setTimeout(function () {
            console.log(2)
        }, 0)
        const p = new Promise((resolve, reject) => {
            resolve(1000)
        })        
        p.then(data => {
            console.log(data)
        })
        console.log(3)
    </script>
</body>

实例3

<body>
    <script>

        console.log(1)
        setTimeout(function () {
            console.log(2)
            new Promise(function (resolve) {
                console.log(3)
                resolve()
            }).then(function () {
                console.log(4)
            })
        })

        new Promise(function (resolve) {
            console.log(5)
            resolve()
        }).then(function () {
            console.log(6)
        })
        
        setTimeout(function () {
            console.log(7)
            new Promise(function (resolve) {
                console.log(8)
                resolve()
            }).then(function () {
                console.log(9)
            })
        })
        console.log(10)

    </script>
</body>

实例4

<body>
    <script>
        console.log(1)

        setTimeout(function () {
            console.log(2)
        }, 0)

        const p = new Promise((resolve, reject) => {
            console.log(3)
            resolve(1000) // 标记为成功
            console.log(4)
        })

        p.then(data => {
            console.log(data)
        })

        console.log(5)
    </script>
</body>

实例5

<body>
    <script>
        new Promise((resolve, reject) => {
            resolve(1)

            new Promise((resolve, reject) => {
                resolve(2)
            }).then(data => {
                console.log(data)
            })

        }).then(data => {
            console.log(data)
        })

        console.log(3)
    </script>
</body>

实例6

<body>
    <script>
        setTimeout(() => {
            console.log(1)
        }, 0)
        new Promise((resolve, reject) => {
            console.log(2)
            resolve('p1')

            new Promise((resolve, reject) => {
                console.log(3)
                setTimeout(() => {
                    resolve('setTimeout2'); //'混淆你的'
                    console.log(4)
                }, 0)
                resolve('p2')
            }).then(data => {
                console.log(data); //'p2'
            })

            setTimeout(() => {
                resolve('setTimeout1'); //'混淆你的'
                console.log(5)
            }, 0)
        }).then(data => {
            console.log(data); //'p1'
        })
        console.log(6)
    </script>
</body>

实例7

<body>
    <script>
        console.log(1);
        async function fnOne() {
            console.log(2);
            await fnTwo(); // 右结合先执行右侧的代码, 然后等待
            console.log(3);
        }
        async function fnTwo() {
            console.log(4);
        }
        fnOne();
        
        setTimeout(() => {
            console.log(5);
        }, 2000);

        let p = new Promise((resolve, reject) => { // new Promise()里的函数体会马上执行所有代码
            console.log(6);
            resolve();
            console.log(7);
        })

        setTimeout(() => {
            console.log(8)
        }, 0)
        
        p.then(() => {
            console.log(9);
        })
        console.log(10);
    </script>
    <script>
        console.log(11);
        setTimeout(() => {
            console.log(12);
            let p = new Promise((resolve) => {
                resolve(13);
            })
            p.then(res => {
                console.log(res);
            })
            console.log(15);
        }, 0)
        console.log(14);
    </script>
</body>