zoukankan      html  css  js  c++  java
  • js异步 从callback 到 async

    js异步

    因为js是单线程的语言,所以为了不使页面卡顿,暂停。js引入了异步机制。

    问:那么js为什么是单线程的呢?

    答:因为js是可以操作dom元素的,所以js就必须单线程的。否则页面渲染就会出问题。

    es6以前的处理方式

    众所周知,es6以前的是通过回掉函数callback来处理异步的逻辑的。这种处理方式正常情况下 没有什么问题,但是如果碰到多个函数层层嵌套 就会出现回掉地狱。形成一个类似于金字塔的样子,虽然执行上并没有问题,但是非常不利于维护和阅读。想想如果 产品经理忽然说需求变了 需要你在b里面在加一段逻辑,再调用一下e函数,然后按照a,b,e,c,d的顺序执行。(这个时候 如果不小心删掉了一个大括号,那么开发人员的心态就会崩溃,怀疑自我。想转行!)(以下代码瞎写的,表达个意思而已,懂吧)

    function  a(){
        function  b(){
            function c(){
                function D(){
                    console.log('a,b,c,d 都按顺序执行了')
                }
            }
        }
    }

    es6的promise

    所以es6的promise应运而生。promise的产生是为了让我们脱离回掉地狱。过上链式调用的好日子。这样代码阅读起来会舒服很多很多。如上面那段逻辑 我们就可以改写为

    function a() {
     return new Promise((resolve,reject)=>{
         return 'a'
     })
    }
    function b() {
        return new Promise((resolve,reject)=>{
            return 'b'
        })
    }
    function c() {
        return new Promise((resolve,reject)=>{
            return 'c'
        })
    }
    function d() {
        return new Promise((resolve,reject)=>{
            return 'd'
        })
    }
    a().then(()=>{
        return b();
    }).then(()=>{
        return c();
    }).then(()=>{
        return d()
    }).then(()=>{
        console.log('a,b,c,d 都按顺序执行了')
    })

    这样的话如果 你要在b 后面加一个e函数 你就可以直接在中间插一段就行了。代码会非常的整齐,逻辑看上去都清晰很多。

    promise 有三种状态,pending, resolved,rejected. 刚定义出来的promise 就是pending状态。 Pending 可以转为resolved 也可以转为rejected 过程不可逆。resolved的状态被then接收,rejected状态可以被catch接收。(这里说的resolved也就是fulfilled的意思)

    es2017的async

    虽然 promise把异步变成了链式调用,但是async 能让我们用同步的语法去写异步的逻辑。这个就很强大,让你写代码的时候 不需要考虑什么同步异步,达到润物无声的高级感。

    我们都知道async 是promise的语法糖,那么怎么理解语法糖这个意思呢,就是说是 他本质上还是promise 的逻辑,但是形式上不一样而已。那怎么证明async不是新的类型呢。可以定义一个async函数,然后直接打印这个函数 就会发现他执行后返回值还是一个promise对象。如下

    async function a(){}  a();
    /*Promise {<fulfilled>: undefined}
    __proto__: Promise
    [[PromiseState]]: "fulfilled"
    [[PromiseResult]]: undefined*/

    async 既然是promise的语法糖,那promise有的功能 它也都有。promises使用时最常用的then函数,在async里面对标的就是await函数。所以 await不能单独调用哦,必须放在async里面。使用方法如下

    async function a(){return 'helloWorld'}
    async function b() {
        console.log("*****")
        let hello=await a();
        console.log(hello);
        console.log("888")
    }
    b();
    //*****
    //helloWorld
    //888

    那promise 对应的catch函数,在这里需要用其它语言的写法,try catch来处理。

    也就是说 要用try来包裹await函数,在catch里写上异常处理逻辑。

    这里有个较为常见的面试题。

    问:我们知道await函数执行过程中,如果中断了,是不会继续往下走的。那如果有的报错,我们其实是希望他提示一下,但是不要中断我的操作,那我们要怎么做呢?

    答:将要处理的这段异步代码用try catch包裹起来,在catch里面加上错误提示,再将try里面包裹的 await后面的代码 再写一份到catch中,让其运行。

    或者,我们可以用async和promise相结合的方式,用promise的catch里面写出错后的逻辑。

    具体代码可以大概概括如下(表达个意思,不是复制出去就能执行的)

    async function a(){return 'helloWorld'}
    async function b() {
        console.log("我是执行异步前的正常逻辑");//1
        try {
            let hello=await a();
            console.log("我是执行异步后的其它代码")//2
        }catch (e) {
            console.error(e)//错误提示
            console.log("我是执行异步后的其它代码")//2语句复制过来的
        }
    
    }
    //或与promise结合
    async function b() {
        console.log("我是执行异步前的正常逻辑");//1
        a().then(()=>{
            console.log("我是执行异步后的其它代码")//2 
        }).catch((e)=>{
            console.error(e)//错误提示
            console.log("我是执行异步后的其它代码")//2语句复制过来的
        })
    }

    异步的处理机制-事件循环

    说到异步 那不能提到异步的处理机制-事件循环(event-loop)

    具体流程 我用下面的简图表示出来了(可能图不太标准 ,主要看文字)

    就是说 一段代码下来,

    1.我们首先判断当前语句是否是同步的正常语句,是的话,我们就推入运行栈中 运行,运行完,将这个语句推出栈。如果碰到异步的语法,我们先把他们放到消息队列里等待着,继续往下走。

    2.如果同步代码已经全部执行完毕,那么运行栈暂时清空,此时,事件循环就好像一个哨兵一样,发现了这个消息,他去消息队列里找我们刚刚暂存在里异步函数,然后继续重复第一步,判断这个异步函数中的语句 是否是同步的。。

    3.事件循环这个哨兵就像永动机一样,不需要休息,一直存在,一直循环监听。就实现了我们的异步逻辑实现。

    宏任务与微任务

    宏任务指的是浏览器指定的一些异步函数,比如点击事件,定时器事件,ajax事件

    微任务指的是js指定的异步函数,比如promise和async await。

    问:为什么要区分宏任务和微任务

    答:因为宏任务和微任务 在事件循环中执行的时机是不一样的。(可能会遇到一些面试题里会问这个)

    问:宏任务和微任务哪个先执行

    答:微任务先执行,宏任务后执行。微任务在dom渲染前执行,宏任务在dom渲染后后执行。(这个就不要问为什么了,人家浏览器就这么定了)

  • 相关阅读:
    微信小程序之登录页实例
    微信小程序之购物车
    微信小程序之加载更多(分页加载)实例
    微信小程序开发之从相册获取图片 使用相机拍照 本地图片上传
    微信小程序--实现图片上传
    关于JavaScriptInterface的一系列问题
    关于websocket,JS客户端和java服务端的林林总总。
    关于JS接高德地图API,以及坐标偏移坐标转换
    Butter Knife:8.0.1的完整正确导入步骤
    android:讲述一下我的第三方支付之路(微信和支付宝)
  • 原文地址:https://www.cnblogs.com/ada-blog/p/13793805.html
Copyright © 2011-2022 走看看