请你谈谈:从宏任务&&微任务的角度谈谈js代码的执行顺序

JavaScript(JS)在浏览器环境中确实是单线程的,这主要出于以下几个原因:

  • JavaScript 的主要作用之一是处理用户的交互,如点击按钮、填写表单等。如果JavaScript是多线程的,那么在处理这些事件时可能会出现竞态条件(race
    conditions),导致用户体验的不可预测性和不一致性。例如,如果两个线程同时尝试修改同一个DOM元素,那么最终的结果将是不可预测的。

我们可以将代码大致分为同步代码(同步任务)和异步代码(异步任务)来理解和处理JavaScript中的执行流程。

  • 同步代码:立即执行,阻塞后续代码,直到执行完成。
  • 异步代码:不立即执行,放入宿主环境的任务队列中,不阻塞主线程,异步结果在将来某个时间点成为可用,并触发相应的回调函数或Promise处理程序执行。

这种异步非阻塞的模型是JavaScript能够高效处理I/O密集型任务(如网络请求、文件读写等)的关键所在。

  • 同步代码是指按照代码书写顺序依次执行的代码。当JavaScript引擎(通常指的是V8、SpiderMonkey等JavaScript解释器)遇到同步代码时,它会立即执行这些代码,并且会“原地等待”直到这些代码执行完成。这里的“原地等待”意味着JavaScript引擎会阻塞后续代码的执行,直到当前同步代码块执行完毕。

    例如,当你执行一个循环或者调用一个函数时,如果这个函数内部不包含异步操作,那么它就是一个同步任务。同步任务会立即执行,并且在下一个任务执行之前,它会完全完成。

  • 异步代码的执行则与同步代码截然不同。当JavaScript引擎遇到异步代码时,它不会立即执行这些代码,而是会将异步操作(如定时器、网络请求、文件读写等)的回调函数或Promise等异步处理机制放入宿主环境(如浏览器或Node.js)的某个任务队列(如宏任务队列或微任务队列)中。然后,JavaScript引擎会继续执行后续的代码,而不会等待异步操作的结果。

    异步操作的结果会在将来的某个时间点成为可用,此时宿主环境会将其对应的回调函数或Promise解决(resolve)或拒绝(reject)的处理程序放入JavaScript引擎的执行栈中执行。这样,即使异步操作需要花费很长时间来完成,JavaScript引擎也不会被阻塞,可以继续处理其他任务。

在JavaScript中,异步任务确实被分为了宏任务(MacroTasks)和微任务(MicroTasks)两大类。

  • 并不是所有由JavaScript引擎发起的任务都是微任务。例如,setTimeoutsetInterval虽然是由JavaScript代码发起的,但它们是由宿主环境(浏览器或Node.js)管理的宏任务。
  • 不同的JavaScript引擎(如V8、SpiderMonkey等)和宿主环境(如不同版本的浏览器或Node.js)之间,在异步任务的处理上可能存在细微的差异。因此,在编写跨平台或跨版本的JavaScript代码时,需要注意这些差异。

宏任务是由宿主环境(如浏览器或Node.js)发起的异步任务。宏任务之间的执行是串行的,即每次只能执行一个宏任务,执行完毕后才会去执行下一个宏任务。它们通常包括:

  • script(整体代码)
  • setTimeout
  • setInterval
  • setImmediate(Node.js特有)
  • I/O
  • UI渲染
  • 事件处理(如点击、滚动等)

微任务是由JavaScript引擎发起的异步任务。与宏任务不同,微任务是在当前宏任务执行完毕后,下一个宏任务开始之前执行的。而且,微任务队列中的任务会按照它们被添加到队列中的顺序依次执行,直到微任务队列为空。它们通常包括:

  • Promise.thenPromise.catchPromise.finally
  • process.nextTick(Node.js特有)
  • MutationObserver(DOM变化观察)
  1. 从上往下执行所有的同步代码
  2. 在执行过程中遇到宏任务就存放到宏任务队列中, 遇到微任务就存放到微任务队列中
  3. 当所有的同步任务执行完毕, 就执行微任务队列中满足需求的所有回调(process.nextTick 优先 )
  4. 当微任务队列中所有满足需求的回调执行完毕后, 就执行宏任务队列中满足需求的所有回调 ( SetImmediate 最后 )
    在这里插入图片描述
1 3 4 5 1000 2

在这里插入图片描述
结果执行顺序为 : 3 2 1
在这里插入图片描述
在这里插入图片描述
输出结果为:11 14 12 15 13
在这里插入图片描述
输出结果为 :2 3 6 p2 p1 1 4 5

async function async1() {
    console.log('async1');
    await async2();
    console.log('async1 end');
}

async function async2() {
    console.log('async2');
}

console.log('script start');
setTimeout(function () {
    console.log('setTimeout');
}, 0);
async1();

在这里插入图片描述

script start
async1
async2
async1 end
setTimeout
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值