JS 异步进阶

1、Event Loop(事件循环/事件轮询)

  1. 同步代码一行一行放在Call Stack(调用栈)执行
  2. 遇到了异步的时候,会把它丢给Web APIs去执行,等待时机
  3. 当时机成熟了,就会吧回调移到Callback Queue(回调队列)
  4. 如果Call Stack为空就说明同步代码执行完了,然后Event Loop开始循环
  5. 轮询查找Callback Queue,如果有的话把它放在Call Stack里面执行

注意:js是单线程的,异步(定时器,ajax)使用回调,是基于event loop的;DOM事件(点击,鼠标滑过)使用回调,也是基于event loop实现的

2、Promise有那三种状态

  • pending,刚创建Promise没有调用resolve或者reject,属于等待待定的状态
  • fulfilled,调用了resolve后,状态就会变为fulfilled,属于完成状态
  • rejected,调用reject以后,状态就会变为rejected,属于拒绝状态

注意状态只能有pending->fulfilled或者pending->rejected,不可逆转

3、Promise里面的then和catch如何影响状态的变化

  1. then正常返回fulfilled,里面有错误返回rejected
  2. catch正常返回fulfilled,里面有错误返回rejected
let a = Promise.resolve(123).then(res=>{
    console.log(res)
})
console.log(a)//fulfilled
let b = Promise.resolve(123).then(res=>{
    throw new Error('bad')
})
console.log(b)//rejected
let c = Promise.reject('bad').catch(err=>{
    console.log(err)
}) 
console.log(c)//fulfilled
let d = Promise.reject('bad').catch(err=>{
    throw new Error('BAD')
    console.log(err)
}) 
console.log(d)//rejected

4、then和catch的链式调用例题

//题目1
Promise.resolve().then(()=>{
    console.log(1)//fulfilled
}).catch(()=>{
    console.log(2)
}).then(()=>{
    console.log(3)//fulfilled
})//1  3
//题目2
Promise.resolve().then(()=>{
    console.log(1)
    throw new Error('k')//rejected
}).catch(()=>{
    console.log(2)//fulfilled
}).then(()=>{
    console.log(3)
})//1  2  3
//题目3
Promise.resolve().then(()=>{
    console.log(1)
    throw new Error('k')//rejected
}).catch(()=>{
    console.log(2)//fulfilled
}).catch(()=>{
    console.log(3)
})//1  2

5、async-await语法

  1. async要和await配合使用
  2. async-await函数其实是通过同步的写法来执行异步
  3. 立即执行函数,要在前面加一个感叹号,否则就会和前面的连接在一起,识别为非法函数
  4. await后面可以接Promise函数,也可以接async函数
function LoadImg(src){
    return new Promise((resolve,reject)=>{
        const img = document.createElement('img')
        img.src = src
        img.onload = function(){
            resolve(img)
        }
        img.reject = function(){
            reject('加载错误')
        }
    })
}
const img1 = 'https://wwc.alicdn.com/avatar/getAvatar.do?userNick=tb376421096&width=60&height=60&type=sns&_input_charset=UTF-8'
const img2 = 'https://gw.alicdn.com/bao/uploaded/i1/15388591/O1CN0105eOif2DKjHQ7d65U_!!15388591.jpg_300x300q90.jpg_.webp'

async function getimg1(){
    let res = await LoadImg(img2)
    return res
}
//立即执行函数,要在前面加一个感叹号,否则就会和前面的连接在一起,识别为非法函数
!(async function(){
	//await后面可以接Promise函数
    let res1 = await LoadImg(img1);
    console.log(res1)
    //await后面也可以接async函数
    let res2 = await getimg1()
    console.log(res2)
})()

6、async-await和Promise的关系

执行async函数,返回的是Promise对象
await相当于Promise的then
try…catch可以捕获异常,相当于Promise的catch

//执行顺序,先是同步的两个输出,然后是立即执行函数,在是fn1的异步
async function fn(){
    return 100//asycn会吧200封装成Promise返回
}
let a = fn().then(r=>{console.log(r)})
console.log(a)
async function fn1(){
    return Promise.resolve(200)
}
let b = fn1().then(r=>{console.log(r)})
console.log(b)
!(async function fn2(){
    // let res = await 300//这里会封装成Promise
    let res = await Promise.resolve(300)
    console.log(res)
})()
!(async function fn3(){
    //try...catch相当于Promise里面的catch
    try{
        let res = await Promise.reject("400")
        console.log(res)
    }catch(err){
        console.log(err)
    }
})()

7、异步的本质

asycn-await的本质还是回调函数,js还是单线程的语言

async function fn1(){
    console.log(2)
    await fn2()//执行到这里先执行普通函数的内容
    //await下面的都是属于回调的内容
    console.log(5)
    await fn3()//执行到这里先执行普通函数的内容
    //await下面的都是属于回调的内容
    console.log(8)
}
async function fn2(){
    console.log(3)
}
async function fn3(){
    await fn4()
    //await下面的都是属于回调的内容
    console.log(7)
}
async function fn4(){
    let res = await 6
    console.log(res)
}
console.log(1)
fn1()
console.log(4)
//1 2 3 4 5 6 7 8

8、for…of的使用场景(遍历异步)

for… of可以解决forEach是同步输出的问题
for…in输出的是键名,for…of输出的是键值
for…in会遍历原型链,性能差,不推荐,for…of只会便利当前对象

function fn1(num){
    return new Promise((resolve,reject)=>{
        setTimeout(() => {
            resolve(num+=1)
        }, 1000);
    })
}
let a = [1,2,3]
a.forEach(async (item)=>{ //这种情况下因为forEach是同步执行的,所以会很快吧所有结果计算出来,然后同时输出
    let res = await fn1(item)
    console.log(res)
})
let b = [4,5,6]
!(async function(){
    try{
        for(let i of a){ //用来for...of 后,会一秒输出一个执行
            let res = await fn1(i)
            console.log(res)
        }
    }catch(e){
        console.log(e)
    }
})()

9、宏任务与微任务

宏任务:setTimeout、setInterval、Ajax,Dom事件(不是异步但是是基于Event Loop)
微任务:Promise、async/await
微任务比宏任务先执行

console.log(1)
//宏任务
setTimeout(()=>{
    console.log(4)
})
//微任务
Promise.resolve(3).then(e=>{
    console.log(e)
})
console.log(2)

10、Event Loop和Dom渲染的联系

  1. 首先执行同步代码,见一个把他放在Call Stack里面执行
  2. 遇到异步的代码,把它放在Web APIs里面处理,然后继续执行同步代码
  3. 当执行完同步代码执行完毕,即Call Stack为空时,这时先尝试Dom渲染
  4. 如果有就先渲染,如果没有就开启Event Loop,从Callback Queue里面执行Web APIs传进来的回调

11、宏任务和微任务的区别

宏任务:DOM渲染后触发
微任务:DOM渲染前触发

12、 宏任务和微任务的根本区别

  1. 首先执行同步代码,见一个把他放在Call Stack里面执行
  2. 遇到异步的代码,把它放在Web APIs里面处理,然后继续执行同步代码,在遇到Promise或者async时,会把它放在Micor Task Queue里面
  3. 当执行完同步代码执行完毕,即Call Stack为空时,这时先去执行微任务队列里面的东西
  4. 然后接着尝试Dom渲染,如果有就先渲染
  5. 如果没有就开启Event Loop,从Callback Queue里面执行Web APIs传进来的回调

13、async-await的面试题

//例1
async function fn(){
    return 100
}
!(async function(){
    let a = fn()
    let b = await fn()
    console.log(a)//Promise对象
    console.log(b)//100
})()
//例题2
!(async function fn1(){
    console.log(1)
    const a = await 2
    console.log(a)
    const b = await Promise.resolve(3)
    console.log(b)
    const c = await Promise.reject(4)
    console.log(c)
    console.log(5)
})() 
//1 2 3 报错(因为await不能处理reject)

14、场景题-外加async- await的顺序问题

async function async1 (){
    console.log(1) //2
    await async2()
    //微任务
    console.log(2)//6
}
async function async2(){
    console.log(3) //3
}
console.log(4)   //1
setTimeout(function (){ //宏任务
    console.log(5) //8
},0)
async1()
new Promise(function(resolve,reject){
    console.log(6) //4
    resolve()
}).then(function(){
    //微任务
    console.log(7) //7
})
console.log(8) //5
// 4 1 3 6 8 2 7 5
//首先执行同步的代码,
//遇到宏任务放在web apis里面,遇到微任务放在micro task queue里面
//完成同步代码,即call stack为空后
//执行微任务(Promise和async)
//渲染DOM
//开始Event Loop,按顺序执行callback queue里面的内容

15、补充Promise.all([a,b,c])和Promise.race([a,b,c])

Promise.all()是等前面的都fulfilled以后,返回一个新的Promise,包含所有的结果
Promise.race()只要有一个为fulfilled,就返回

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值