最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 前端笔记(异步进阶)

    正文概述 掘金(爱吃薯条的Ray)   2021-03-16   629

    题目

    - 请描述event loop (事件循环/事件轮询)的机制,可画图

    见event loop 图示

    - 什么是宏任务和微任务,两者有什么区别?

    见 宏任务

    - Promise有那三种状态?如何变化?

    见Promise 三种状态

    - promise then 和 catch 的连接

    前端笔记(异步进阶)

    // 第一题
    Promise.resolve().then(() => {
        console.log(1) //1
    }).catch(() => {
        console.log(2)
    }).then(() => {
        console.log(3) //3
    })
    
    // 第二题
    Promise.resolve().then(() => { // 返回 rejected 状态的 promise
        console.log(1) //1
        throw new Error('erro1')
    }).catch(() => { // 返回 resolved 状态的 promise
        console.log(2) //2
    }).then(() => {
        console.log(3) //3
    })
    
    // 第三题
    Promise.resolve().then(() => { // 返回 rejected 状态的 promise
        console.log(1) //1
        throw new Error('erro1')
    }).catch(() => { // 返回 resolved 状态的 promise
        console.log(2) //2
    }).catch(() => {
        console.log(3)
    })
    

    - async/await 语法

    前端笔记(异步进阶)

    // 代码1
    async function fn() {
      return 100
    }
    (async function(){
      const a = fn(); //Promise
      const b = await fn() //100
    })()
    //代码2
    (async function(){
      console.log('start') //打印 'start'
      const a = await 100
      console.log("a",a) //打印 100
      const b = await Promise.resolve(200)
      console.log('b',b) //打印 200
      const c = await Promise.reject(300) //报错 后面代码不执行
      console.log('c',c) 
      console.log('end')
    })() 
    

    - proimse 和 setTimeout的顺序

    前端笔记(异步进阶)

    console.log(100)
    setTimeout(() => {
      console.log(200)
    })
    Promise.resolve().then(()=>{
      console.log(300)
    })
    console.log(400)
    

    - async/await 的顺序问题

    前端笔记(异步进阶)

    async function async1 () {
      console.log('async1 start')
      await async2() // 这一句会同步执行,返回 Promise ,其中的 `console.log('async2')` 也会同步执行
      console.log('async1 end') // 上面有 await ,下面就变成了“异步”,类似 cakkback 的功能(微任务)
    }
    
    async function async2 () {
      console.log('async2')
    }
    
    console.log('script start')
    
    setTimeout(function () { // 异步,宏任务
      console.log('setTimeout')
    }, 0)
    
    async1()
    
    new Promise (function (resolve) { // 返回 Promise 之后,即同步执行完成,then 是异步代码
      console.log('promise1') // Promise 的函数体会立刻执行
      resolve()
    }).then (function () { // 异步,微任务
      console.log('promise2')
    })
    
    console.log('script end')
    
    // 同步代码执行完之后,屡一下现有的异步未执行的,按照顺序
    // 1. async1 函数中 await 后面的内容 —— 微任务
    // 2. setTimeout —— 宏任务
    // 3. then —— 微任务
    
    

    知识点

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

    • JS是单线程
    • 异步要基于回调来实现
    • DOM时间也使用回调,基于eventloop实现
    • event loop 就是异步回调的实现原理

    JS是如何执行的

    • 从前到后,一行一行执行
    • 如果某一行执行报错,则停止下面代码的执行
    • 先把同步代码执行完,在执行异步

    示例

    console.log('Hi')
    
    setTimeout(function cb1(){
        console.log('cb1') // cb 即 callback
    },5000)
    
    console.log('Bye')
    

    图示

    前端笔记(异步进阶)

    前端笔记(异步进阶) 总结event loop 过程

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

    Promise

    三种状态

    • pending(在过程中还没有结果) fulfilled(已经解决了成功) rejected(被拒绝了失败了) resolved(已敲定状态)===settled(即执行结束后状态就锁定了)
    • pending --->fulfilled 或 --->rejected --->resolved===settled

    状态的变化和表现

    • pending 状态,不会触发then和catch
    • fulfilled状态,会触发后续的then回调函数
    • rejected状态,会触发后续的catch回调函数

    then和catch对状态的影响

    • then正常返回fulfilled,里面有报错则返回rejected
    • catch正常返回fulfilled,里面有报错则返回rejected
    // then() 一般正常返回 fulfilled 状态的 promise
    Promise.resolve().then(() => {
        return 100
    })
    
    // then() 里抛出错误,会返回 rejected 状态的 promise
    Promise.resolve().then(() => {
        throw new Error('err')
    })
    
    // catch() 不抛出错误,会返回 fulfilled 状态的 promise
    Promise.reject().catch(() => {
        console.error('catch some error')
    })
    
    // catch() 抛出错误,会返回 rejected 状态的 promise
    Promise.reject().catch(() => {
        console.error('catch some error')
        throw new Error('err')
    })
    

    async/await

    简介

    • 异步回调 callback hell
    • Proimse then catch 链式调用,但也是基于回调函数
    • async/await 是同步语法,彻底消灭回调函数

    语法

    function loadImg(src) {
        const promise = new Promise((resolve, reject) => {
            const img = document.createElement('img')
            img.onload = () => {
                resolve(img)
            }
            img.onerror = () => {
                reject(new Error(`图片加载失败 ${src}`))
            }
            img.src = src
        })
        return promise
    }
    
    async function loadImg1() {
        const src1 = 'http://www.imooc.com/static/img/index/logo_new.png'
        const img1 = await loadImg(src1)
        return img1
    }
    
    async function loadImg2() {
        const src2 = 'https://avatars3.githubusercontent.com/u/9583120'
        const img2 = await loadImg(src2)
        return img2
    }
    
    (async function () {
        // 注意:await 必须放在 async 函数中,否则会报错
        try {
            // 加载第一张图片
            const img1 = await loadImg1()
            console.log(img1)
            // 加载第二张图片
            const img2 = await loadImg2()
            console.log(img2)
        } catch (ex) {
            console.error(ex)
        }
    })()
    

    async/await 和Promise的关系

    • 执行async函数,返回的是Promise对象
      • async 函数返回结果都是 Promise 对象(如果函数内没返回 Promise ,则自动封装一下)
    async function fn2() {
        return new Promise(() => {})
    }
    console.log( fn2() )
    
    async function fn1() {
        return 100
    }
    console.log( fn1() ) // 相当于 Promise.resolve(100)
    
    • await相当于Promise的then
      • await 后面跟 Promise 对象:会阻断后续代码,等待状态变为 resolved ,才获取结果并继续执行
      • await 后续跟非 Promise 对象:会直接返回
    (async function () {
        const p1 = new Promise(() => {})
        await p1
        console.log('p1') // 不会执行
    })()
    
    (async function () {
        const p2 = Promise.resolve(100)
        const res = await p2
        console.log(res) // 100
    })()
    
    (async function () {
        const res = await 100
        console.log(res) // 100
    })()
    
    (async function () {
        const p3 = Promise.reject('some err')
        const res = await p3
        console.log(res) // 不会执行
    })()
    
    • try...catch可捕获异常,代替了Promise的catch
    (async function () {
        const p4 = Promise.reject('some err')
        try {
            const res = await p4
            console.log(res)
        } catch (ex) {
            console.error(ex)
        }
    })()
    

    总结

    • async 封装 Promise
    • await 处理 Promise 成功
    • try...catch 处理 Promise 失败

    异步本质

    • async/await 是消灭异步回调的终极武器
    • JS还是单线程,还要异步,还是基于event loop
    • async/await 只是一个语法糖,但真香!
    • await 是同步写法,但本质还是异步调用
    async function async1 () {
      console.log('async1 start')
      await async2()
      console.log('async1 end') // 关键在这一步,它相当于放在 callback 中,最后执行
    }
    
    async function async2 () {
      console.log('async2')
    }
    
    console.log('script start')
    async1()
    console.log('script end')
    

    即,只要遇到了 await ,后面的代码都相当于放在 callback 里。

    for...of

    • for...in(以及forEach for) 是常规的同步遍历 表现为先执行,有结果一块出来
    • for...of常用于异步的遍历,表现为一个有结果再执行下一个
    // 定时算乘法
    function multi(num) {
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve(num * num)
            }, 1000)
        })
    }
    
    // // 使用 forEach ,是 1s 之后打印出所有结果,即 3 个值是一起被计算出来的
    // function test1 () {
    //     const nums = [1, 2, 3];
    //     nums.forEach(async x => {
    //         const res = await multi(x);
    //         console.log(res);
    //     })
    // }
    // test1();
    
    // 使用 for...of ,可以让计算挨个串行执行
    async function test2 () {
        const nums = [1, 2, 3];
        for (let x of nums) {
            // 在 for...of 循环体的内部,遇到 await 会挨个串行计算
            const res = await multi(x)
            console.log(res)
        }
    }
    test2()
    

    宏任务(macro Task)和微任务(micro Task)

    什么是宏任务,什么是微任务

    • 宏任务:setTimeout,setInterval,Ajax,DOM事件
    • 微任务:Promise async/await
    • 微任务执行时机比宏任务要早

    event loop 和 DOM渲染

    要回顾一下event loop的执行过程

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

    图示:

    前端笔记(异步进阶)

    代码例子:

    const $p1 = $('<p>一段文字</p>')
    const $p2 = $('<p>一段文字</p>')
    const $p3 = $('<p>一段文字</p>')
    $('#container')
                .append($p1)
                .append($p2)
                .append($p3)
    
    console.log('length',  $('#container').children().length )
    alert('本次 call stack 结束,DOM 结构已更新,但尚未触发渲染')
    // (alert 会阻断 js 执行,也会阻断 DOM 渲染,便于查看效果)
    // 到此,即本次 call stack 结束后(同步任务都执行完了),浏览器会自动触发渲染,不用代码干预
    
    // 另外,按照 event loop 触发 DOM 渲染时机,setTimeout 时 alert ,就能看到 DOM 渲染后的结果了
    setTimeout(function () {
        alert('setTimeout 是在下一次 Call Stack ,就能看到 DOM 渲染出来的结果了')
    })
    

    微任务和宏任务的区别

    • 宏任务:DOM渲染之后触发,如setTimeout
      • PS:宏任务是浏览器或者 nodejs 的 API ,不在 ES 语法规范之内,也不是 js 引擎执行,而是浏览器或 nodejs 的内核来执行。
    • 微任务:DOM渲染前触发,如Promise
      • PS:微任务是 ES 语法的规范,是 js 引擎(如 v8)执行的

    图示:

    前端笔记(异步进阶) PS:Firefox中:DOM会在微任务执行之前执行。即DOM->微任务->宏任务


    起源地下载网 » 前端笔记(异步进阶)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元