前端必须要会的同步异步知识点(包含经典面试题)

知识点

  • 单线程和异步
    js是单线程语言,只能同时做一件事
    浏览器和nodejs已支持js启动进程,如web worker
    js和dom共用同一个线程,因为js可以修改DOM结构
  • 应用场景
    网络请求,如ajax图片加载
//ajax
console.log('start')
$.get("./data1.json",function(res){
console.log(res)
})
console.log('end')
//图片加载
console.log('start')
 let img = document.createElement('img')
 img.onload = function(){
console.log('loaded')
}
img.src = '/xx.png'
console.log('end')

定时任务

  • callback hell和Promise

call stack 调用栈
Web APIs
Callback Queue 回调函数队列

event loop过程
同步代码,一行一行放在 Call Stack执行
遇到异步,会先记录下来,等待时机(定时、网络请求等)
时机到了,就移动到Callback Queue
如Call Stack(即同步代码执行完)Eventloop开始工作
轮询查找Callback Queue,如有则移动到Call Stack执行
然后继续轮询查找(永动机一样)

DOM事件与eventloop
js是单线程
异步(setTimeout,ajax,等)使用回调,基于eventloop
DOM事件也使用回调,基于eventloop
但DOM事件不是异步

Promise
三种状态:pedding fulfilled rejected

状态的表现和变化
then和catch对状态的影响

then正常返回fulfilled,里面有报错则返回rejected
catch正常返回fulfilled,里面有报错则返回rejected

const p1 =Promise.resolve().then(()=>{
	return 100
})
console.log("p1",p1)//fulfilled

const p2 = Promise.resolve().then(()=>{
	throw new Error("then error")
})
console.log("p2",p2)//rejected

const p3 = Promise.reject('my error').catch(err=>{
    console.error(err)
})
console.log('p3',p3) //fulfilled

const p4 = Promise.reject('my error').catch(err=>{
    throw new Error('then err')
})
console.log('p4',p4) //rejected

promise链式调用面试题

Promise.resolve().then(()=>{
    console.log(1)
}).catch(()=>{
    console.log(2)
}).then(()=>{
    console.log(3)
})//1 3

// 第二题
Promise.resolve().then(()=>{
    console.log(1)
    throw new Error("erro1")
}).catch(()=>{
    console.log(2)
}).then(()=>{
    console.log(3)
})// 1 2 3

// 第三题
Promise.resolve().then(()=>{
    console.log(1)
    throw new Error("erro1")
}).catch(()=>{
    console.log(2)
}).catch(()=>{
    console.log(3)
})//1 2

async/await
异步回调callback hell
Promise then catch 链式调用,但也是基于回调函数
aysnc/await是同步语法,彻底消灭回调函数
await可以追加promise函数和aysnc函数

async/await和Promise的关系

1. 执行async函数,返回的是Promise对象
2. await相当于Promise的then
3. try...catch可捕获异常,代替了Promise的catch
代码演示:

async function fun1(params) {
    return 100//相当于Promise.resolve(100)
}
const res = fun1()//执行async函数,返回的是Promise对象 
console.log(res)//Promise {<fulfilled>: 100}
res.then(data=>{
    console.log('data',data)//data 100
})


async function fun2(params) {
    return Promise.resolve(200)
}
const res2 = fun2()//执行async函数,返回的是Promise对象 
console.log(res2)//Promise {<fulfilled>: 200}
res2.then(data=>{
    console.log('data',data)//data 200
})
!(async function(){
    const p1 = Promise.resolve(300)
    const data1 = await p1//await相当于Promise then
    console.log('data1',data1)//data1 300
})()
!(async function(){
    const data2 = await 400//await相当于Promise then
    console.log('data2',data2)//data1 400
})()

即使async函数用await返回也是promise

//即使async函数用await返回也是promise
async function fun1(params) {
    return await 100
}
const res = fun1()
console.log(res)//Promise {<fulfilled>: 100}
res.then(data=>{
    console.log('data',data)//data 100
})
//try...catch可捕获异常,代替了Promise的catch
!(async function(){
    const p4 =Promise.reject('err')
    try{
        const res4 = await p4
        console.log(res4)
    }catch(ex){
        console.error(ex)//err
    } 
})()
!(async function(){
    const p4 =Promise.reject('err')
    const res4 = await p4//await--->then
    console.log(res4)//不会执行
})()

异步本质
async/await是消灭异步回调的终极武器
js还是单线程,还得是有异步,还得是基于event loop
async/await只是一个语法糖

代码演示
await 的后面,都可以看做是callback里的内容,即异步

async function async1(){
    console.log('async1 start')//第二步
    await async2()//undefined
    //await 的后面,都可以看做是callback里的内容,即异步
    //类似,event loop,setTimeout
    console.log('async1 end')//第五步
}

async function async2(){
    console.log("async2")//第三步
}

console.log('script start')//第一步
async1()
console.log('script end')//第四步

执行顺序
script start
async1 start
async2
script end
async1 end

for…of
for…in(以及forEach for)是常规的同步遍历
for…of常用语异步的遍历

function muti(num){
    return new Promise(resolve=>{
        setTimeout(()=>{
            resolve(num*num)
        },1000)
    })
}

const nums = [1,2,3]

// forEach是同步,会一直执行,把setTimeout放在统一放在web api,时间到了,放在eventloop执行,
// 所以会过了一秒一起打印三个数 
nums.forEach(async(i)=>{
    const res = await muti(i)
    console.log(res)
})

// for...of,会等待执行,一秒打印一个
!(async function(){
    for(var k of nums){
        const res = await muti(k)
        console.log(res)
    }
})()

宏任务macroTask和微任务 microTask

  1. 什么是宏任务,什么是微任务
  2. event loop和DOM渲染
  3. 宏任务和微任务的区别
console.log(100)//第一步
//宏任务
setTimeout(()=>{
   console.log(200)//第四步
})
//微任务
Promise.resolve().then(()=>{
   console.log(300)//第三步
})
console.log(400)//第二步

宏任务和微任务
宏任务:setTimeout、setIntetval、Ajax、DOM事件
微任务:Promise.then async/await
微任务执行时机比宏任务要早(先记住)

eventloop和DOM渲染
每次Call Stack清空(即每次轮询结束),即同步任务执行完
都是DOM重新渲染的机会,DOM结构如有改变则重新渲染
然后再去触发下一次Event Loop

宏任务:DOM渲染后触发,如setTimeout
微任务:DOM渲染前触发,如Promise.then
  • 为什么微任务比宏任务执行的早?
    微任务是ES6语法规定的
    宏任务是由浏览器规定的

执行步骤
1、Call Stack清空
2、执行当前的微任务
3、尝试DOM渲染
4、触发Event Loop

面试题 执行顺序

async function async1() {
    console.log('async1 start')//2
    await async2()
    // await相当于执行promise.then,后面代码为微任务
     console.log('async1 end')//6
}
async function async2(){
    console.log('async2')//3
}

console.log("script start")//1

setTimeout(()=>{//宏任务
    console.log('setTimeout');//8
},0)

async1()

new Promise(function(resolve){
    console.log('promise1')//4
    resolve()
}).then(function(){//微任务
    console.log('promise2')//7
})

console.log('script end')//5
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值