事件循环(Event Loop)

JS 是单线程

        JavaScript 是一种单线程的编程语言同一时间只能做一件事,所有任务都需要排队依次完成。

        为什么 JS 不能有多个线程呢?
        答:作为浏览器脚本语言,JS 的主要用途是与用户互动,以及操作 DOM这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定 JS 同时有两个线程,一个线程在某个 DOM 节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?为了避免这种复杂性,因此 JS 只能是单线程

事件循环机制(Event Loop)

        含义:告诉了我们 JS 代码的执行顺序,是指浏览器或 Node 的一种解决 JS 单线程运行时不会阻塞的一种机制。

        Event Loop事件循环,其实就是 JS引擎 管理事件执行的一个流程,具体由运行环境确定。目前 JS 的主要运行环境有两个,浏览器和 Node。

1、同步任务与异步任务

同步任务

立即放入 JS引擎(JS 主线程)中执行,并原地等待结果。

异步任务

先放入宿主环境(浏览器/node),不必原地等待结果,并不阻塞主线程继续往下执行,异步结果在将来执行

分类:异步任务分为宏任务和微任务。所有同步任务都在主线程上执行,形成一个函数调用栈(执行栈),而异步任务则先放到任务队列task queue)里,任务队列又分为宏任务(macro-task)与微任务(micro-task)。 

宏任务

由宿主(浏览器、node)发起的任务

  • script(代码块)
  • setTimeout/setInterval 定时器
  • setImmediate(node)
  • 事件绑定的回调
  • I/O
  • UI交互事件 等等

微任务

由 JS引擎 发起的任务

  • process.nextTick(node)
  • Promise.then(回调) catch();Promise本身同步,then/catch的回调函数是异步的
  • Async/Await;在 await 后面的代码都属于微任务,相当于调用 Promise.then方法
  • Object.observe(已废弃) 等等

2、执行过程

  1. 同步任务由 js引擎 执行,异步任务交给宿主环境
  2. 所有同步任务在主线程中执行,形成一个执行栈(调用栈)
  3. 主线程之外,还存在一个‘任务队列’(task queue),当异步的代码运行完毕以后,会将代码中的回调送入到任务队列中(队列遵循先进先出得原则)
  4. 主线程的执行栈执行完毕后,会去任务队列看是否由异步任务,有就送到主线程的执行栈执行,反复循环查看执行,这个过程就是事件循环(Event Loop)

3、执行顺序

  • 先执行同步代码,
  • 遇到宏任务时要先达到触发条件,才将宏任务放入宏任务队列,
    • 比如:事件绑定;两个定时器,2秒的在前,1秒的在后,先执行的是1秒的定时器
  • 遇到微任务则将微任务放入微任务队列中,
  • 当所有同步代码执行完后,再将微任务从队列中调入主线程执行,
  • 微任务执行完毕后再将宏任务调入主线程执行
  • 一直循环(同步任务 > 微任务 > 宏任务 > 同步任务...)直至所有任务执行完毕。

注意:当宏任务和微任务都处于 任务队列(Task Queue) 中时,微任务的优先级大于宏任务,即先将微任务执行完,再执行宏任务;

4.、实例

 // 假设这是我们要请求的数据
    function getSomething (n) {
      return new Promise(resolve => {
        console.log('Promise 中是同步任务');
        // 模拟1s后返回数据
        setTimeout(() => resolve(222), 1000);
      });
    }

    // 如果想要等数据返回后再执行后面的代码,那么就要使用 async/await
    async function real () {
      console.log(111);
      // 这时something会等到异步请求的结果回来后才进行赋值,同时不会执行之后的代码
      const something = await getSomething();
      console.log(something)
      console.log('await后面是微任务');
    }
    real()

    console.log(333);

解析

在 await 后面的代码都属于微任务,相当于调用 Promise.then方法,所以要等 resolve 之后才会执行 await 后面的代码,await 里面的代码还是遵循事件循环。在同一作用域内看上去就是同步的,但如果上一个作用域中还有同步任务,还是会先执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值