JavaScript是单线程语言
- 单线程执行任务队列的问题: 如果前一个任务非常耗时,则后续任务不得不等待,从而导致程序假死的问题。
同步任务和异步任务
为了防止某个耗时任务程序导致假死的问题,javascript把待执行的任务分为两类:
同步任务(synchronous)
- 又叫非耗时任务,指的是主线程上排队执行的任务
- 按照顺序执行
异步任务(asynchronous)
- 又叫耗时任务,异步任务由javascipt委托给
宿主环境
进行执行 - 当异步任务执行完成后,会通知javascipt主线程执行异步任务的回调函数
同步任务和异步任务的执行过程
-
同步任务由javascipt主线程按
次序执行
-
异步任务委托给宿主环境执行
-
已完成的异步任务对应的回调函数,会被加入到
任务队列
中等待执行 -
javascript主线程的执行栈中被
清空
后,会读取任务队列中的回调函数,按次序执行(这个动作不断重复 也叫eventloop
)
总结:
首先,js主线程会从自己的执行栈中按照顺序去执行所有的任务,
当发现是同步任务的时候,由js主线程自己执行。发现是异步任务时,
就委托给宿主环境进行执行。这样js主线程就能继续执行其他的同步任务(非耗时任务)。
最后js主线程发现执行栈中的同步任务都被执行完后,此时js主线程会从任务队列中,按照顺序
把对应的回调函数取出来,放到执行栈中,依次去执行。
EvenLoop事件循环
Javascipt主线程
从任务队列
读取异步任务的回调函数,放到执行栈中依次执行。- 这个过程是循环不断的,所以这个机制称为
Evenloop事件循环
。
EventLoop经典面试题
import thenFs from "then-fs";
console.log('A')
thenFs.readFile('./file/01.txt', 'utf8').then(dataStr => {
console.log('B')
})
setTimeout(() => {
console.log('C')
}, 0)
console.log('D') //
- 执行顺序为: ADCB
- A和D属于同步任务。js主线程按顺序依次执行
- B和C属于异步任务。它们的回调函数放到任务队里中,等待主线程空闲时再执行。
宏任务与微任务
1.宏任务(macrottask)
ajax
,setIimeout
,setInterval
,文件操作
等
2.微任务(microttaks)
Promise.then
,.catch
和.finally
,process.nextTick
等
宏任务和微任务的执行顺序
- 每一个宏任务执行完后,都会先
检查
是否存在待执行
的微任务 - 如果有,则执行所有微任务后,再继续执行下一个宏任务
- 宏任务和微任务是
交替执行
的
宏任务和微任务经典面试题
setTimeout(function () { // 宏任务
console.log('1')
})
new Promise(function (resolve) { // 同步任务
console.log('2')
resolve()
}).then(function () { // 微任务
console.log('3')
})
console.log('4') // 同步任务
- 执行顺序为: 2431
- 先执行所有同步任务,再检查待执行的微任务,有就执行微任务,然后继续下一个宏任务。
console.log('1') // 同步任务1
setTimeout(function () { // 宏任务1
console.log('2')
new Promise(function (resolve) {
console.log('3')
resolve()
}).then(function () { // 微任务
console.log(4)
})
})
new Promise(function (resolve) { // 同步任务2
console.log('5')
resolve()
}).then(function () { // 微任务
console.log('6')
})
setTimeout(function () {
console.log('7')
new Promise(function (resolve) { // 宏任务2
console.log('8')
resolve()
}).then(function () { // 微任务
console.log('9')
})
})
- 执行顺序是: 156234789
总结:
先执行第一行的同步任务,发现2~12属于宏任务,放到宏任务队列中排队等待执行
然后就到了13行,执行了该同步任务,16的微任务放到微任务队列中等待执行,
再然后发现20~30是一个宏任务,放到宏任务队列。此时同步任务全部执行完,
检查是否有待执行的微任务,有6。然后微任务队列清空了,接下来就执行宏任务队列中第一个延时器,
然后又立即执行了里面的new..里的funcion,然后.then放到微任务队列等待执行。然后此时
要执行下一个宏任务,先检查有没有等待执行的微任务,有4,然后微任务队列队列清空了。
然后再执行下一个宏任务(第二个延时器),然后又立即执行了new..里的funcion,然后.then放到微任务列表待执行。
此时宏任务执行完毕,检查微任务队列有没有待执行的微任务,有9。