资讯详情

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=>span class="token punctuation">{
     
       
    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,就返回

标签: 12vdc继电器q90f

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台