1. 什么是同步什么是异步
js 是单线程,也就是一次只能做一件事情,所以,如果遇到特别耗费时间的代码,就会导致卡住(页面在转圈),所以,为了解决这个问题,js 就把代码分为两种,一种是同步代码,一种是异步代码(所谓的异步代码指的就是耗时任务,比如 ajax,定时器,触发的 DOM 事件)
2. 事件环 event loop
-
浏览器是多线程的(浏览器可以边听音乐边看知乎)
-
js 代码是从上往下执行,遇到同步代码直接在 js 栈中执行,遇到异步的代码,比如遇到一个定时器,就把异步代码交给浏览器,让浏览器为这个定时器分配一个独立的线程专门计时,遇到 ajax 也是让浏览器分配一下线程专门发送 ajax
-
异步代码如果到了需要触发的时机(定时器就是设定的时间到,ajax 就是数据拿回来),它们在拿回来的时候 js 引擎还在忙,它们只能去排队先进先出(类似核酸检测)
-
当 js 执行栈把代码全部执行完的时候,它就会去 callback queue(回调函数队列)去看有没有回调函数在排队,如果有就把它拿到执行栈中去执行,回调函数里面也可能有一堆的同步异步,所以又会导致新的异步回调去排队,这样就会循环往复执行下去,我们把这个称为 event loop
3. 宏任务和微任务
什么是宏任务
定时器、ajax这些东西需要单独开一个线程,不是js本身的东西(是webapi的东西),我们把它们称为宏任务,
什么是微任务
还有一种是promise,async await这些是ecmascrpit本身语法的东西,我们把它们称为微任务
4. 执行顺序
同步代码 -> 微任务 -> 宏任务 -> 微任务 -> 宏任务 + new Promise是同步的 只有then,catch是异步 + async,await --> await后面写的相当写在then里面
例题1、
console.log(1)
setTimeout(function() {
console.log(2)
}, 0)
new Promise(function(resolve) {
console.log(3)
resolve()
}).then(function() {
console.log(4)
})
console.log(5)
结果:1、3、5、4、2
例题2、
async function async1() {
console.log('async1 start')
await async2()
// await后面的代码可以理解为promise.then(function(){ 回调执行的 })
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(function() {
console.log('setTimeout')
}, 0)
async1()
console.log('script end')
结果:script start、async1 start、async2、script end、async1 end、setTimeout