美文网首页
JS异步-解决方法简述

JS异步-解决方法简述

作者: hui树 | 来源:发表于2020-03-04 17:18 被阅读0次

    介绍三种异步处理方案:

    回调函数(callback)
    promise
    async/await

    回调函数(callback)

    回调函数应该属于最简单粗暴的一种方式,主要表现为在异步函数中将一个函数进行参数传入,当异步执行完成之后执行该函数

    话不多说,上代码:

    // 有三个任务console.log(1)console.log(2)console.log(3)
    // 过5s执行任务1,任务1执行完后,再过5s执行任务2.....
    window.setTimeout(function(){
        console.log(1)
        window.setTimeout(function(){
            console.log(2)
            window.setTimeout(function(){
                console.log(3)
            },5000)
        },5000)
    },5000)
    

    看出这种方式的缺点了吗?没错,试想,如果再多几个异步函数,代码整体的维护性,可读性都变的极差,如果出了bug,修复的排查过程也变的极为困难,这个便是所谓的 回调函数地狱 。

    promise

    promise简单的说就是一个容器,里面保存着某个未来才会结束的时间(通常是一个异步操作)的结果。从语法上说,Promise就是一个对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同样的方法处理。

    promise有所谓的 4 3 2 1

    4大术语

    解决(fulfill)
    拒绝(reject)
    终值(eventual value)
    据因(reason)

    3种状态

    等待态(Pending (也叫进行态)
    执行态(Fulfilled)(也叫成功态)
    拒绝态(Rejected) (也叫失败态)

    2种事件

    如果是pending –> fulfiied,就会触发onFulFilled事件
    如果是pendeing –> rejected,就会触发onRejected事件

    1个对象

    promise

    注:只有异步操作的结果,可以决定当前是哪一种状态,任何其他的操作都无法改变这个状态

    简单来讲,就还是promise中有着三种状态pending,fulfilled,rejected。在代码中我们可以控制状态的变更

    new Promise(function(resolve,reject){
        console.log("pending");
        console.log("pending");
        resolve();
        reject();
    })
    

    创建一个Promise对象需要传入一个函数,函数的参数是resolve和reject,在函数内部调用时,就分别代表状态由pending=>fulfilled(成功),pending=>rejected(失败)

    一旦promise状态发生变化之后,之后状态就不会再变了。比如:调用resolve之后,状态就变为fulfilled,之后再调用reject,状态也不会变化

    Promise对象在创建之后会立刻执行,因此一般的做法是使用一个函数进行包装,然后return一个promise对象

    function betray(){
        return new Promise(function(resolve,reject){
            ...//异步操作
        })
    }
    

    在使用时可以通过promise对象的内置方法then进行调用,then有两个函数参数,分别表示promise对象中调用resolve和reject时执行的函数

    function betray(){
        return new Promise(function(resolve,reject){
            setTimeout(function(){
                resolve();
            },1000)
        })
    }
    
    betray().then(function(){
        ...//对应resolve时执行的逻辑
    },function(){
        ...//对应reject时执行的逻辑
    })
    

    可以使用多个then来实现链式调用,then的函数参数中会默认返回promise对象

    betray().then(function(){
        ...//对应resolve时执行的逻辑
    },function(){
        ...//对应reject时执行的逻辑
    })
    .then(function(){
        ...//上一个then返回的promise对象对应resolve状态时执行的逻辑
    },function(){
        ...//上一个then返回的promise对象对应reject状态时执行的逻辑
    })
    

    使用promise来解决回调地狱的做法就是使用then的链式调用

    function fnA(){
        return new Promise(resolve=>{
            ...//异步操作中resolve
        })
    }
    function fnB(){
        return new Promise(resolve=>{
            ...//异步操作中resolve
        })
    }
    function fnC(){
        return new Promise(resolve=>{
            ...//异步操作中resolve
        })
    }
    
    fnA()
    .then(()=>{
        return fnB()
    })
    .then(()=>{
        return fnC()
    })
    

    async/await

    async、await是什么?

    async顾名思义是“异步”的意思,async用于声明一个函数是异步的。而await从字面意思上是“等待”的意思,就是用于等待异步完成。并且await只能在async函数中使用

    通常async、await都是跟随Promise一起使用的。为什么这么说呢?因为async返回的都是一个Promise对象同时async适用于任何类型的函数上。这样await得到的就是一个Promise对象(如果不是Promise对象的话那async返回的是什么 就是什么);

    await得到Promise对象之后就等待Promise接下来的resolve或者reject。

    async、await解决了什么?

    传统的回调地狱式写法:

    getData(a=>{
        getMoreData(a,b=>{
            getMoreData(b,c=>{
                console.log(c)
            });
        });
    });
    //不行了,再多写要迷了
    

    Promise改进后的写法:

    getData()
    .then(a=>getMoreData(a))
    .then(b=>getMoreData(b))
    .then(c=>getMoreData(c))
    

    async/await改进后:

    (async()=>{
        const a = await getData;
        const b = await.getMoreData(a);
        const c = await.getMoreData(b);
        const d = await.getMoreData(c);
    })();
    

    async、await写法

    先来看看同步写法:

    console.log(1);
    
    setTimeout(function () {
      console.log(2);
    }, 1000);
    
    console.log(3);
    

    输出结果:

    1
    3
    undefined
    2
    

    可以看到输出的顺序并不是我们代码中所写的那样,下面来看下async、await是如何解决这个问题的

    (async function () {
    
      console.log(1);
    
      await new Promise(function (resolve, reject) { 
        setTimeout(function () {
          console.log(2);
          resolve();
        }, 1000);
      });
    
      console.log(3);
    
    }())
    

    输出结果:

    1
    Promise
    2
    3
    

    可以看到这种写法的输出已经符合了我们的预期,中间还多输出了一个Promise对象

    async 的定义:

    async函数会返回一个Promise对象
    如果async函数中是return一个值,这个值就是Promise对象中resolve的值
    如果async函数中是throw一个值,这个值就是Promise对象中reject的值

    await 的定义:

    await只能在async里面
    await后面要跟一个promise对象
    常规的promise对象会被js先暂存到eventloop(事件队列)中,因为js是单线程执行的,等执行栈空了之后,才会将事件队列中的事件取出放入执行栈中执行

    上述代码中先是将整段代码改造成了一个async(async可以用于任何函数)函数,然后又将setTimeOut改造成了一个Promise对象

    以上就是解决JS异步的三种方法

    (网络资源整理而来)

    相关文章

      网友评论

          本文标题:JS异步-解决方法简述

          本文链接:https://www.haomeiwen.com/subject/eejblhtx.html