为什么任务要分同步和异步?宏任务与微任务又有何区别? (结合面试题理解)

JavaScript是单线程的,也就是说,同一个时刻,JavaScript只能执行一个任务,其他任务只能等待。
1.为什么JavaScript是单线程的?
js是运行于浏览器的脚本语言,因其经常涉及操作dom,如果是多线程的,也就意味着,同一个时刻,能够执行多个任务。
试想,如果一个线程修改dom,另一个线程删除dom,那么浏览器就不知道该先执行哪个操作。
所以js执行的时候会按照一个任务一个任务来执行。
2.为什么任务要分为同步任务和异步任务?
【为什么任务要分同步和异步?宏任务与微任务又有何区别? (结合面试题理解)】试想一下,如果js的任务都是同步的,那么遇到定时器、网络请求等这类型需要延时执行的任务会发生什么?
页面可能会瘫痪,需要暂停下来等待这些需要很长时间才能执行完毕的代码
所以,又引入了异步任务。

  • 同步任务:同步任务不需要等待可立即看到执行结果,比如console
  • 异步任务:异步任务需要等待一定的时候才能看到结果,比如setTimeout、网络请求
异步任务,又可以细分为宏任务和微任务。下面列举目前学过的宏任务和微任务。
任务(代码) 宏/微 任务 环境
script 宏任务 浏览器
事件 宏任务 浏览器
网络请求(Ajax) 宏任务 浏览器
setTimeout() 定时器 宏任务 浏览器 / Node
fs.readFile() 读取文件 宏任务 Node
Promise.then() 微任务 浏览器 / Node
他们的执行过程是怎样的呢?
比如去银行排队办业务,每个人的业务就相当于是一个宏任务;
比如一个人,办的业务有存钱、买纪念币、买理财产品、办信用卡,这些就叫做微任务。
为什么任务要分同步和异步?宏任务与微任务又有何区别? (结合面试题理解)
文章图片

执行顺序:
为什么任务要分同步和异步?宏任务与微任务又有何区别? (结合面试题理解)
文章图片

概念
1.宏任务:当前调用栈中执行的代码成为宏任务。(主代码快,定时器等等)。
2.微任务: 当前(此次事件循环中)宏任务执行完,在下一个宏任务开始之前需要执行的任务,可以理解为回调事件。(promise.then,proness.nextTick等等)。
3.宏任务中的事件放在callback queue中,由事件触发线程维护;微任务的事件放在微任务队列中,由js引擎线程维护。
事件循环(Event Loop)
事件循环就是一个在 "JavaScript 引擎等待任务","执行任务"和"进入休眠状态等待更多任务"这几个状态之间转换的无限循环。
引擎的一般算法:
  1. 当有任务时:
    • 从最先进入的任务开始执行。
  2. 休眠直到出现任务,然后转到第 1 步。
常见面试题
1.
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)// 运行结果: 1, 3, 1000, 2

面试题分析:
先分析有几次事件循环? 有两次事件循环:第一次先运行script标签里面的内容,在执行栈中运行后,先打印的是 1, 3; 在运行过程中遇到的微任务是要加到微任务队列里面等待,当执行栈中的任务运行完后,在执行微任务,即打印 1000,此时第一次循环结束,第二次循环在执行栈中运行定时器,则最总输出结果是:1, 3, 1000, 2
2.
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)// 运行结果 : 1 5 10 6 2 3 4 7 8 9

3.
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)// 运行结果: 1 3 4 5 1000 2

4.
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) })setTimeout(() => { resolve('setTimeout1') console.log(5) }, 0) }).then(data => { console.log(data) }) console.log(6)// 运行结果: 2 3 6 p2 p1 1 4 5

为什么任务要分同步和异步?宏任务与微任务又有何区别? (结合面试题理解)
文章图片

可以做一下题,加强理解

    推荐阅读