侧边栏壁纸
博主头像
uvdream博主等级

一切皆有可能!

  • 累计撰写 37 篇文章
  • 累计创建 21 个标签
  • 累计收到 18 条评论

【查漏补缺】javascript的Eventloop,宏任务,微任务

uvdream
2021-09-04 / 4 评论 / 13 点赞 / 739 阅读 / 3,212 字
温馨提示:
本文最后更新于 2022-04-08,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

JavaScript 的 EventLoop,宏任务,微任务

js 中的线程

js为什么是单线程

js单线程的特点就是同一时刻只能执行一个任务

js单线程主要由于一些用户的互动以及操作dom等相关的操作决定了js要使用单线程,否则使用多线程会带来复杂的同步问题.

如果一个线程正在修改dom,另一个线程在删除dom,那么以哪个为准?

如果执行同步问题的话,多线程需要加锁,执行任务会非常繁杂

虽然HTML5标准规定,允许javascript脚本创建多个线程,但是子线程完全受主线程控制,且不可以操作dom

单线程带来的问题

阻塞,当一个任务执行完成之后才能执行下一个任务 ,这样就会导致页面卡死状态,页面无响应,影响用户体验,所以不得不出现同步任务和异步任务的解决方案.

同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务

异步任务:不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,才会将进入主线程执行

js如何实现异步编程

  • 所有同步任务都在主线程,形成一个执行栈
  • 主线程外还存在一个任务队列,只要异步任务有运行结果,就是任务队列之中放置一个事件
  • 一旦执行栈那种所有同步任务执行完毕,系统就读取任务队列,看看里面哪些异步任务执行完毕,进入执行栈开始执行
  • 主线程不断重复上述三步

EventLoop

几个概念:

  • 执行上下文(Execution context)
  • 执行栈(Execution stack)
  • 微任务(micro-task)
  • 宏任务(macro-task)

执行上下文

函数执行前进行的准备工作(也称执行上下文环境)

运行javascript代码时候,当代码进入一个环境时,就会为改环境创建一个执行上下文,他会在你运行代码前做一些准备,例如确定作用域,创建局部变量对象等

javascript执行上下文类型

  • 全局环境:代码首次执行时的默认环境
  • 函数环境:每当执行流程进入到一个函数体内部的时候
  • Eval函数:执行eval函数内部的代码也会有它属于自己的执行上下文

执行栈

数据结构中的栈,先进后出

let a = "1"
    function first() {
        console.log("first 1")
        second()
        console.log("first 2")
    }
    function second() {
        console.log("second");
    }
    first()
    console.log("执行全局");
  • 初始化状态,执行栈任务为空;
  • fist()函数执行,first()进入执行栈,输入"first 1",碰到函数second()
  • second()进入执行栈,开始执行second()函数,输出"second"
  • second()函数执行完出栈,继续执行栈顶端的函数first(),输出"first 2"
  • first()出栈,执行下面输出"执行全局"

事件循环

宏任务

可以理解为每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)

浏览器为了能使得js内部宏任务与DOM任务有序的执行,会在一个宏任务执行结束后,在下一个宏任务执行开始前,对页面重新渲染(宏任务=>渲染=>宏任务=>…)

宏任务包括

  • script(整体代码)
  • setTimeout
  • setInterval
  • I/O
  • UI交互事件
  • postMessage
  • MessageChannel
  • setImmediate(nodejs)

定时器

微任务

可以理解为当前宏任务执行结束后立即执行的任务

微任务包括

  • Promise.then()
  • Object.observe
  • MutaionObserver
  • process.nextTick

宏任务微任务运行机制

执行机制

宏任务和微任务

主线程上添加宏任务与微任务

console.log("start");
setTimeout(() => {
    console.log("setTimeout");
});
new Promise((resolve) => {
    console.log("promise");
    resolve("成功");
}).then((res) => {
    console.log(res);
});
console.log("end");

[结果]:

start

promise

end

成功

setTimeout

执行顺序:主线程=>主线程上创建的微任务=>主线程上创建的宏任务

微任务中创建微任务

console.log('1');
setTimeout(() => {
    console.log('2');
})
new Promise(resolve => {
    resolve()
    console.log('3');
}).then(() => {
    console.log('4');
    Promise.resolve().then(() => {
        console.log('5');
    }).then(() => {
        console.log('6');
    })
})
console.log('7');

[结果]:

1

3

7

4

5

6

2

执行顺序:主线程=>主线程上创建的微任务=>微任务上创建的微任务=>主线程上创建的宏任务

同时两个微任务执行

console.log('1');
setTimeout(() => {
    console.log('2');
})
new Promise(resolve => {
    console.log('3');
    resolve()
}).then(() => {
    console.log('4');
    Promise.resolve().then(() => {
        console.log('5');
    }).then(() => {
        console.log('6');
    })
}).then(() => {
    console.log('7');
})
console.log('8');

[结果]:

1

3

8

4

5

7

6

2

宏任务中创建微任务

console.log('1');
setTimeout(() => {
    console.log('2');
    setTimeout(() => {
        console.log('3');
    })
    new Promise(resolve => {
        console.log('4');
        resolve()
    }).then(() => {
        console.log('5');
    })
})
setTimeout(() => {
    console.log('6');
})
console.log('7');

[结果]:

1

7

2

4

5

6

3

微任务中创建宏任务

console.log('1');
new Promise(resolve => {
    console.log('2');
    resolve()
}).then(() => {
    console.log('3');
    setTimeout(() => {
        console.log('4');
    })
})
setTimeout(() => {
    console.log('5');
})
console.log('6');

[结果]:

1

2

6

3

5

4

0

评论区