原贴链接:javascript异步实战

今天的主角是async await
之前说过async 就是 Generator 的语法糖

Generator简单回顾

看一段伪代码(纯展示逻辑,跑不起来的)

  1. function* getData() {
  2. yield loadData1()//“这个执行成功后执行it.next(),启动下一个yield,没有yield就执行return,没有return 就是return undefined”
  3. yield loadData2()//“这个执行成功后执行it.next(),启动下一个yield,没有yield就执行return,没有return 就是return undefined”
  4. yield loadData3()//“这个执行成功后执行it.next(),启动下一个yield,没有yield就执行return,没有return 就是return undefined”
  5. }
  6. const it = getData()it.next()//“启动生成器”

执行的逻辑看上面的代码注释,真正处理异步的时候,我相信很多人不会使用Generator来处理,至少我不会,太麻烦了
这时候async来了,它的出现大大简化了Generator的使用

async简单介绍

上面的伪代码,用async来实现

  1. async function getData() {
  2. await loadData1()
  3. await loadData2()
  4. await loadData3()
  5. }
  6. getData()

async就像是Generator中的“*”,await就相当于Generator中的yield,同样的,await只能在使用了async的函数内使用

关于async的返回

一个小栗子

  1. async function doSth() {
  2. const GJ = '郭靖在发呆'
  3. }
  4. console.log(doSth());
  5. //=>Promise {<resolved>: undefined}

async 自动把函数转换为 Promise,返回的是一个Promise对象
关于async的介绍的文章,多如牛毛,不再赘述,进入主题

异步实战

还是那个需求

现在有接口1,接口2,接口3 按顺序输出接口1,接口2,接口3的值

我们上一次分别用了回调函数嵌套,原生的Promise,以及Generator来实现的这个功能 ajax是使用jquery

在写法上还是有些“hello world”,因为内容太理论,我们下面采用axios+async来实现
上面的需求也可以这么理解,先调用接口一,接口二的执行依赖于接口一的返回,接口三的执行依赖于接口二的返回
所以,接口一,接口二,接口三,需要同步的按顺序执行
众所周知,axios返回的一个Promise对象,下面的栗子依赖于这一特性
为了简化demo的流程,方便大家实战操作,我没有搭建webpack或者babel环境,
就是新建了一个html页面,在浏览器控制台查看效果
因为兼容问题,建议使用Chrome浏览器进行操作
首先

  1. <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

js部分,easy-mock上面有三个接口,接口一和接口二的返回值很简单,接口三返回值是长度在10-20之间的数组,
以保证接口三的返回时间要长一些,以体现异步效果

  1. // 一个函数p11,返回一个axios,Promise对象
  2. function p11() {
  3. return axios('https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/promise1')
  4. .then(({data}) => {
  5. if (data.data.name) {
  6. return data.data.name
  7. }
  8. })
  9. }
  10. // 一个函数p22,返回一个axios,Promise对象
  11. function p22() {
  12. return axios('https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/promise2')
  13. .then(({data}) => {
  14. if (data.data.name) {
  15. return data.data.name
  16. }
  17. })
  18. }
  19. // 一个函数p33,返回一个axios,Promise对象
  20. function p33() {
  21. return axios('https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/mock')
  22. .then(({data}) => {
  23. if (data.success) {
  24. return data.data.projects
  25. }
  26. })
  27. }

三个请求已经封装完毕,函数没没有console.log
作为比较,也作为复习,我们看下Promie的实现

  1. p11()
  2. .then(res1 => {
  3. console.log(res1);
  4. return p22()
  5. })
  6. .then(res2 => {
  7. console.log(res2);
  8. return p33()
  9. }).then(res3 => {
  10. console.log(res3);
  11. return res3
  12. })

输出

image.png

对此没什么可以赘述的

async 处理异步

再我们看下async

  1. async function asyncFUn() {
  2. const RES1 = await p11();
  3. console.log(RES1);
  4. const RES2 = await p22();
  5. console.log(RES2);
  6. const RES3 = await p33();
  7. console.log(RES3);
  8. return RES3;
  9. }
  10. asyncFUn()

await的存在 使异步变成了同步
在处理异步的时候,await后面要根的是一个返回Promise的函数
就像上面的p11,p22,p33,函数都是返回一个axios(axios返回一个Promise对象),如果不是,就用Promise包装一下
否则会出现这样的结果

  1. <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
  2. function loadData1() {
  3. $.ajax({
  4. url: "https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/promise1",
  5. success: ({
  6. data,
  7. success
  8. }) => {
  9. if (success) {
  10. console.log(`接口一返回:${data.name}`);
  11. return data.name
  12. }
  13. }
  14. });
  15. }
  16. function loadData2() {
  17. $.ajax({
  18. url: "https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/promise2",
  19. success: ({
  20. data
  21. }) => {
  22. console.log(`接口二返回:${data.name}`);
  23. return data.name
  24. }
  25. });
  26. }
  27. function loadData3() {
  28. $.ajax({
  29. url: "https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/mock",
  30. success: ({
  31. data,
  32. success
  33. }) => {
  34. if (success) {
  35. console.log('接口三返回', data.projects);
  36. return data.projects
  37. }
  38. }
  39. });
  40. }
  41. async function asyncFUn1() {
  42. const RES1 = await loadData1();
  43. console.log(RES1);//=>undefined
  44. const RES2 = await loadData2();
  45. console.log(RES2);//=>undefined
  46. const RES3 = await loadData3();
  47. console.log(RES3);//=>undefined
  48. return RES3;
  49. }
  50. asyncFUn1()

输出

这时候就需要用Promise进行包装。类似于这样

  1. function loadData1() {
  2. return new Promise((resolve, reject) => {
  3. $.ajax({
  4. url: "https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/promise1",
  5. success: ({
  6. data,
  7. success
  8. }) => {
  9. if (success) {
  10. console.log(`接口一返回:${data.name}`);
  11. resolve(data.name)
  12. }
  13. }
  14. });
  15. })
  16. }

如果不是异步,那就没有必要通过await来处理了,当然await后面也支持非异步,可以自行实践

async 处理报错

看到了,async中没有then catch,怎么处理报错信息呢?
天无绝人之路,使用try catch

  1. async function asyncFUn() {
  2. const RES1 = await p11();
  3. console.log(RES1);
  4. const RES2 = await p22();
  5. console.log(RES2);
  6. const RES3 = await p33();
  7. console.log(RES3);
  8. return RES3;
  9. }
  10. try {
  11. asyncFUn()
  12. } catch (error) {
  13. console.log(error);
  14. }

好,关于async await 就介绍到这里
END