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


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张图片

概念

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

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


可以做一下题,加强理解

你可能感兴趣的:(前端javascript)