异步、Promise和async-await

异步的科普

我们新银医中经常会需要调用异步加载的方法—async-await,但是很多人只是知道可以这么用,但是不知道为什么要这么用,以及什么情况下能这么用,写这篇文章的目的就是为了解答这些疑惑,但是由于本人也只是一个小菜鸟,所以有些地方如果不对还请给我指出,这样我们可以共同进步,那么我们开始吧。

一、  什么是异步

异步就是不等任务执行完就执行下一个任务,与之相对的就是同步,它必须等一个任务执行完了才能执行下一个,拿泡茶来类比,异步就是你可以一边烧水一边洗茶具,等水烧好了就可以直接泡茶了,同步就是你只能等水烧好了才能去洗茶具然后才能去泡茶,烧水期间不能做别的事情。

由此可以得出两个结论:第一,需要做两样互不干扰的事(比如烧水和洗茶具)的时候,用异步是比较合适的;第二,需要拿到结果才能进行下一件事的时候,必须要用同步,比如说,必须拿到热水才能泡茶,所以什么时候用异步是需要好好思考一下环境的。

二、  Promise

Es6中最重要的一个特性,用来解决异步操作中可能会出现的多层回调,将整个函数包裹成一个promise对象,并且规定了promise对象是一个构造函数,统一提供接口,方便使用和维护。

promise出现背景

在promise出现之前,js要想实现异步操作必须使用回调函数得到异步操作的结果,一个两个还好,如果需要多个异步操作,就会层层嵌套,那么代码就会陷入回调地狱里,非常不利于阅读和维护。下面就是一个活生生的例子:

所以在es6中推出了promise这样一个避免回调地狱的实现形式,可以将异步操作以同步操作的流程表达出来,上面这个例子用promise的形式写出来就是这样:

这个例子用了promise的链式操作方法,相比之下确实容易阅读。注意:then方法中的return 的作用是把值传递到下一个then中。

Promise的特性

①  promise的核心在于“状态”,总共有三个状态:pending(正在进行)、resolved(处理完成,通常被叫做fulfilled)和rejected(处理失败)。

②  这些状态不受外界影响,当promise被创建时,promise处于pending状态,当promise里面的函数调用resolve()就会转变为resolved(fulfilled)状态,如果promise里面的函数调用reject()则会转变为rejected状态;

③  状态不可逆,一旦完成了pendingàresolved/rejected的转换,就不能够再回到pending状态;

Promise的用法

Promise的标准里有以下几种方法:resolve(),reject(),then(),catch(),all(),race()。这里有一个小细节需要注意,一旦构建了promise,它就会自动执行,所以通常情况下会把promise包在一个函数里面,例如:

①  resolve():将promise的状态修改为resolved(fulfilled),此时;

②  reject():将promise的状态修改为rejected;

③  then(fn1,fn2):

fn1是resolve()的回调方法,而fn2是reject()的回调方法。

Then()方法内通过return 可以返回三种值,第一种是返回一个promise对象;第二种是返回一个同步值;第三种是抛出异常,如果是第一种,则会发生这种情况:

注意:then函数的执行方式是异步的,比如:

这里执行顺序就是①-③-②。

Promise的方法链:then方法注册的回调会依次被调用,每个then方法之间通过return 返回值传递参数(请参考promise的例子)此处需注意:用promise的方法链的时候,如果其中一个then中有了异常,用catch捕获后会输出这样的异常信息:

这个就是promise令人诟病的地方之一,方法链中出了错,错误的堆栈信息并不直观。

④  catch(fn):用来捕获和处理promise中的异常,和then(fn1,fn2)中的fn2不同的是,catch()可以捕获fn1里面的错误,所以推荐用catch()来捕获和处理异常。

⑤  all([fn1,fn2,fn3…]):使fn1,fn2,fn3等函数全部都执行完了再一起输出结果,且fn1,fn2,fn3等函数是同时执行的。

⑥  race([fn1,fn2,fn3…]): fn1,fn2,fn3等函数谁先执行完(他们是同时执行的)就输出谁的结果,此处需要注意的是,输出结果后,流程继续往下走,但是fn2,fn3等函数仍然在执行。

三、  Async-await

async是es8中出现的,被很多人称之为异步的终极解决方法。了解promise之后,才能了解async,因为async是基于promise的语法糖,包裹了async的函数会隐式的返回一个promise对象,await可以将其后的代码转化为同步的原因是因为await本质上就是把其后的代码包裹在promise的then函数中强制代码按照顺序执行,所以await必须写在async函数里面.

Async-await PK promise

1、代码简洁,语法优美。相比于promise来说async的代码更加容易看懂,还是拿promise中第一个例子,用async来写的话是这样:

2、异常堆栈信息清晰易懂。

3、异步的概念更加弱化,同步异步之间的转换更方便。

Async-await特性

1、Await只会影响直接包裹它的async函数,举个反面例子:

就会报错:

2、await 命令后面,可以跟 Promise 对象(使用了async-await的函数也是promise对象),和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。

3、命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try...catch 代码块中,也可以用promise自带的catch()来捕获和处理异常,如下:

Async-await的用法

使用方法:在需要等待的异步代码前面加上await,在直接包含await的方法前面加async;

扩展用法:可以在添加了async的函数后面添加then()方法进行回调,promise的方法async都能用


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章