JS异步-解决方法简述

2020-03-04  本文已影响0人  hui树

介绍三种异步处理方案:

回调函数(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异步的三种方法

(网络资源整理而来)

上一篇下一篇

猜你喜欢

热点阅读