异步(进阶)--event loop,promise进阶,async/await

event loop(事件循环/事件轮询)  

JS是单线程运行的

异步是基于回调来实现的

event loop就是异步回调的基本原理

event loop执行过程,简单图示

过程简述:1、当调用栈执行第一行代码后,在浏览器输出结果,并清空调用栈;

2、调用栈执行setTimeout函数(异步),在Web APIs中生成一个定时任务,等待触发回调,然后清空调用栈,此步骤无输出结果;

3、调用栈执行最后一行,在浏览器输出结果,清空调用栈;

4、前三步会在ms单位执行完毕,此时调用栈为空,启动event loop,它会往回调队列读取触发的回调函数,若为空,则继续轮询等待;当定时任务等异步事件被触发,就会被放到回调队列中,经event loop送到调用栈中执行,此时cb1函数被执行,在浏览器打印结果。

 

 总结event loop执行过程

  • 同步代码,一行行放在Call Stack中执行
  • 遇到异步,会先“记录”下,等待时机(网络请求、定时等)
  • 时机到了,就移动到Callback Queue
  • 若Call Stack为空(同步代码执行完),Event loop则开始工作
  • 轮询查找Callback Queue,若有则移动到Call Stack中执行
  • 然后继续轮询查找(像永动机)

DOM和 Event loop

    <button id="bn1">提交</button>
    <script>
        console.log('Hi');
        $('#bn1').click( () =>{
            console.log('button click');
        })
        console.log('Bye');
    </script>

DOM事件(不是异步)也使用回调函数,原理基于回调,也基于Event loop。触发时机是用户的交互,Call stack执行click这行代码,将箭头函数存在Web APIs中,等待用户触发,再移动到Callback Queue执行下面的操作

Promise三种状态

  • pending、resolved(或者叫fulfilled)、rejected
  • pending -> resolved 或 pending -> rejected
  • 变化不可逆
        const p1 = new Promise((resolve, reject) => {

        })
        console.log('p1',p1);//pending

        const p2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve()
            })
        })
        console.log('p2',p2);//pending 一开始打印时;执行setTimeout()后 resolved
        setTimeout(() => {console.log('p2-setTimeout',p2);})    //resolved

        const p3 = new Promise((resolve, reject) => {
            setTimeout(() => {
                reject()
            })
        })
        console.log('p3',p3);//pending 一开始打印时;执行setTimeout()后 rejected

状态的表现

  • pending状态,不会触发then 或 catch
  • resolved状态(也称fulfilled),会触发后续的then 
  • rejected状态,会触发后续的catch
    <script>
        const p1 = Promise.resolve(100);
        console.log('p1',p1);   //resolved或者显示fulfilled
        p1.then(data => {       
            console.log('data',data);   //100
        }).catch(err => {       //不会执行catch
            console.log(err);
        })

        const p2 = Promise.reject('error');
        console.log('p2',p2);
        p2.then(data => {   //rejected状态,直接执行catch
            console.log('data',data);
        }).catch(err => {
            console.log(err); //'error'
        })
    </script>

then 和 catch改变状态

  • then正常返回resolved,里面有报错则返回rejected
  • catch正常返回resolved,里面有报错则返回rejected
    <script>
        const p1 = Promise.resolve().then(()=> {
            return 100;
        })
        console.log('p1',p1);       //resolved或者显示fulfilled,触发then
        const p2 = Promise.resolve().then(()=> {
            throw new Error('p2-error')
        })    
        console.log('p2',p2);       //rejected,可以触发catch
        p2.then(()=>{}).catch(()=>{})     //此时触发catch

        const p3 = Promise.reject().catch(()=> {
            return 300;
        })
        console.log('p3',p3);       //resolved

        const p4 = Promise.resolve().then(()=> {
            throw new Error('p4-error')
        })
        console.log('p4',p4);       //rejected
    </script>
  • 关于then和catch面试

        Promise.resolve().then(() =>{
            console.log(1);
        }).catch(()=> {
            console.log(2);
        }).then(()=> {
            console.log(3);
        })
        //1,3 resolve()触发then(),第一个then没有抛出错误,正常返回resolved,触发第二个then,结        果输出1,3 


        Promise.resolve().then(()=> {
            console.log(1);
            throw new Error('error')
        }).catch(() => {
            console.log(2);
        }).then(()=> {
            console.log(3);
        })
        //输出1,2,3 resolved状态触发第一个then,打印1后抛出错误,返回状态rejected,触发catch,打印2未抛出新错误,返回状态resolved,触发下一个then 


        Promise.resolve().then(() => {
            console.log(1);
            throw new Error('error');   //rejected
        }).catch(()=> {
            console.log(2);     //resolved,不再触发下一个catch
        }).catch(()=> {
            console.log(3);
        })

 

async-await

async-await是用同步的写法而非回调的写法写异步;

async/await和Promise并不互斥,是相辅相成的

       function loadImg(src) { 
            const p = new Promise((resolve, reject) => {
                const img = document.createElement('img')
                img.onload = () => {
                    resolve(img)
                }
                img.onerror = () => {
                    const err = new Error(`图片加载失败 ${src}`)
                    reject(err)
                }
                img.src = src
            })
            return p
        }
        const src1 = 'https://www.imooc.com/static/img/index/logo2020.png'
        
        //Promise的写法
        // loadImg(src1).then(img =>{
        //     console.log(img.width);
        //     return img
        // }).then(img => {
        //     console.log(img.height);
        // }).catch(ex => { console.error(ex) })

        //async/await
        //注意,! 可以帮助把前后文隔开,在前文未写分号的情况下,不会把二者认成一个函数
        !(async function() {
            //同步的写法
            const img1 = await loadImg(src1);
            console.log(img1.width, img1.height);
        })()

async-await和 Promise的关系

  • 执行async函数,返回的是Promise对象
  • await相当于Promise的then
  • 可用try...catch的方式捕获异常,代替了Promise的catch(其他语言都是用try...catch,更合理)

 执行async函数,返回的是Promise对象

        async function fn1() {
            //return 100; //返回的是一个Promise对象,相当于 return Promise.resolve(100)
            return Promise.resolve(200);
        }

        const res1 = fn1() //执行async函数,返回的是一个Promise对象
        //console.log('res1', res1); //Promise对象
        res1.then(data => {
            console.log('data', data);
        })

await相当于Promise的then

        !(async function() {
            const p1 = Promise.resolve(3000)
            const data = await p1;  //(1)跟Promise对象,await 相当于 Promise.then
            console.log('data',data);
        })()
        
        !(async function() {
            const data1 = await 300; //(2)跟一个值,300被封装成Promise对象
            console.log('data1',data1);
        })()

        async function fn() {
            return 100; //返回的是一个Promise对象,相当于 return Promise.resolve(100)
        }

        !(async function() {
            const data2 = await fn(); //(3) 跟一个async函数
            console.log('data2',data2); //100
        })()

 可用try...catch的方式捕获异常,代替了Promise的catch

        !(async function() {
            const p4 = Promise.reject('err')
            try {
                const res = await p4
                console.log(res); //前一句抛出错误,这一句不会打印
            } catch(ex) {
                console.error(ex);  //try...catch 相当于 Promise的catch
            }
        })()

        !(async function() {
            const p5 = Promise.reject('err1')
            const res = await p5  //await相当于Promise的 then,rejected状态下不会被执行
            console.log(res);
        })

 总结:异步的本质

  • async/await 是消灭回调的终极武器
  • JS是单线程,还是得有异步,还是得基于 event loop
  • async/ await 是一个语法糖,从语法层面用类似同步的写法解决异步回调(callback hell),但消灭不了异步,因为上一点始终成立;(await 后面都可以看做异步回调 callback的内容)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值