乐趣区

关于前端:为什么任务要分同步和异步宏任务与微任务又有何区别-结合面试题理解


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


能够做一下题, 增强了解

退出移动版