本文主要是介绍请你谈谈:从宏任务微任务的角度谈谈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引擎发起的任务都是微任务。例如,
setTimeout
和setInterval
虽然是由JavaScript代码发起的,但它们是由宿主环境(浏览器或Node.js)管理的宏任务。 - 不同的JavaScript引擎(如V8、SpiderMonkey等)和宿主环境(如不同版本的浏览器或Node.js)之间,在异步任务的处理上可能存在细微的差异。因此,在编写跨平台或跨版本的JavaScript代码时,需要注意这些差异。
宏任务是由宿主环境(如浏览器或Node.js)发起的异步任务。宏任务之间的执行是串行的,即每次只能执行一个宏任务,执行完毕后才会去执行下一个宏任务。它们通常包括:
script
(整体代码)setTimeout
setInterval
setImmediate
(Node.js特有)I/O
UI渲染
事件处理
(如点击、滚动等)
微任务是由JavaScript引擎发起的异步任务。与宏任务不同,微任务是在当前宏任务执行完毕后,下一个宏任务开始之前执行的。而且,微任务队列中的任务会按照它们被添加到队列中的顺序依次执行,直到微任务队列为空。它们通常包括:
Promise.then
、Promise.catch
、Promise.finally
process.nextTick
(Node.js特有)MutationObserver
(DOM变化观察)
- 从上往下执行所有的同步代码
- 在执行过程中遇到宏任务就存放到宏任务队列中, 遇到微任务就存放到微任务队列中
- 当所有的同步任务执行完毕, 就执行微任务队列中满足需求的所有回调(process.nextTick 优先 )
- 当微任务队列中所有满足需求的回调执行完毕后, 就执行宏任务队列中满足需求的所有回调 ( 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
这篇关于请你谈谈:从宏任务微任务的角度谈谈js代码的执行顺序的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!