乐趣区

关于javascript:ES6-Promise-和-asyncawait-的使用

你可能晓得,Javascript 语言的执行环境是 ” 单线程 ”(single thread)。

所谓 ” 单线程 ”,就是指一次只能实现一件工作。如果有多个工作,就必须排队,后面一个工作实现,再执行前面一个工作,以此类推。

这种模式的益处是实现起来比较简单,执行环境绝对单纯;害处是只有有一个工作耗时很长,前面的工作都必须排队等着,会迁延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段 Javascript 代码长时间运行(比方死循环),导致整个页面卡在这个中央,其余工作无奈执行。

为了解决这个问题,Javascript 语言将工作的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。

1. 回调

回调是异步编程最根本的办法。

假设有两个函数 f1 和 f2,后者期待前者的执行后果。

f1();
f2();

如果 f1 是一个很耗时的工作,能够思考改写 f1,把 f2 写成 f1 的回调函数。

function f1(callback){setTimeout(function () {
    // f1 的工作代码
    callback();}, 1000);
}

执行代码就变成上面这样

f1(f2);

采纳这种形式,咱们把同步操作变成了异步操作,f1 不会梗塞程序运行,相当于先执行程序的次要逻辑,将耗时的操作推延执行。回调函数的长处是简略、容易了解和部署,毛病是不利于代码的浏览和保护,各个局部之间高度耦合,流程会很凌乱,而且每个工作只能指定一个回调函数。

2.Promise

Promises对象是 CommonJS 工作组提出的一种标准,目标是为异步编程提供对立接口。

简略说,它的思维是,每一个异步工作返回一个 Promise 对象,该对象有一个 then 办法,容许指定回调函数。Promises 的呈现大大改善了异步变成的窘境,避免出现回调天堂,嵌套层级失去改善。

根本 Api

Promise.resolve()
Promise.reject()
Promise.prototype.then()
Promise.prototype.catch()
Promise.all()  // 所有的实现
Promise.race() // 竞速,实现一个即可

具体 api 的介绍请看 阮一峰 大神的 ECMAScript 6 入门
在这我举几个简略的场景的实现

模仿两个异步申请

为了使代码简介,Promiserejected 状态的相干 reject()catch()办法省略

  // 1 申请
  function getData1 () {return new Promise(function (resolve, reject) {setTimeout(() => {console.log('1 执行了')
        resolve('申请到模仿数据 1111 拉')
      }, 2000)
    })
  }
  // 2 申请
  function getData2 (params) {return new Promise(function (resolve, reject) {setTimeout(() => {console.log('2 执行了')
        resolve('申请到模仿数据 22222 拉!params:' + params)
      }, 1500)
    })
  }

promise 实现异步回调 异步列队

1 申请实现后,把 1 的响应参数传入 2,在发 2 申请

  function promiseDemo () {getData1()
      .then(res => {return getData2(res)
      })
      .then(res => {console.log(res)
      })
  }
  promiseDemo()
  // 1 执行了
  // 2 执行了
  // 申请到模仿数据 22222 拉!params:申请到模仿数据 1111 拉   用时 3500 ms

promise.all() 实现异步回调 并发 所有的实现

1 申请、2 申请同时发, 两条响应都收到后再执行

  function promiseDemo () {Promise.all([getData1(), getData2()]).then(function (res) {console.log(res)
    })
  }
  // 2 执行了
  // 1 执行了
  // ["申请到模仿数据 1111 拉", "申请到模仿数据 22222 拉!params:undefined"]   用时 2000 ms

promise.race() 实现异步回调 并发 竞速

1 申请、2 申请同时发,其中一条收到申请就执行

  function promiseDemo () {Promise.race([getData1(), getData2()]).then(function (res) {console.log(res)
    })
  }
  // 2 执行了
  // 申请到模仿数据 22222 拉!params:undefined    用时 1500 ms
  // 1 执行了

由此 Promise 对象还是很好用的,对于异步的流程的管制失去了大大改善,通过 .then() 的办法可进行链式调用。可是 .then() .catch() 应用也导致代码十分难看,嵌套也很深,所以 async/await 就进去了

3.Async/await

async/await 是 Javascript 编写异步程序的新办法。以往的异步办法无外乎回调函数和 Promise。然而async/await 建设于 Promise 之上。

如何应用 Async 函数

咱们还是来看一看 阮一峰 大神的 ECMAScript 6 入门的例子

async function timeout(ms) {await new Promise((resolve) => {setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 50);

下面代码指定 50 毫秒当前,输入 hello world。
进一步说,async 函数齐全能够看作多个异步操作,包装成的一个 Promise 对象,而 await 命令就是外部 then 命令的语法糖

咱们看具体的示例

async 实现异步回调 异步列队

1 申请实现后,把 1 的响应参数传入 2,在发 2 申请

上文中的 promise 实现办法是通过 then 的链式调用,然而采纳 async 会更加简洁明了

  async function asyncDemo () {const r1 = await getData1()
    const r2 = await getData2(r1)
    console.log(r2)
  }
  // 1 执行了
  // 2 执行了
  // 申请到模仿数据 22222 拉!params:申请到模仿数据 1111 拉   用时 3500 ms

用同步的书写形式实现了异步的代码。期待 getData1 的异步函数执行完了后发返回值赋值给 r1,传入 r2, 在执行 r2

async 异步回调 并发

1 申请、2 申请同时发, 规定申请达到的程序

如果咱们有一种这样的业务需要,并发两个申请,然而要规定收到申请的程序应该怎么做的?这里还是借鉴阮一峰大神的代码

  async function asyncDemo2 () {const arr = [getData1, getData2]
    const textPromises = arr.map(async function (doc) {const response = await doc()
      return response
    })
    // 按秩序输入
    for (const textPromise of textPromises) {console.log(await textPromise);
    }
  }
  // 2 执行了            (因为 2 是 1500ms 后执行) 所以 2 先执行
  // 1 执行了
  // 申请到模仿数据 1 拉  (for .. of)规定了输入的程序
  // 申请到模仿数据 22222 拉!params:undefined

下面代码中,尽管 map 办法的参数是 async 函数,但它是并发执行的,因为只有 async 函数外部是继发执行,内部不受影响。前面的 for..of 循环外部应用了 await,因而实现了按程序输入

async 总结

它使得异步代码变的不再显著也是一点弊病咯,不过依据理论状况抉择最合适的异步编程才是最好的抉择。async 是 Generator 函数的语法糖。所以想更深刻的了解其中外部原理的连忙去看看 Generator函数把

退出移动版