一、async函数

MDN上对于async function的定义:

  1. When an async function is called, it returns a Promise.When the async function returns a
  2. value, the Promise will be resolved with the returned value. When the async function
  3. throws an exception or some value, the Promise will be rejected with the thrown value.

也就是说async函数会返回一个Promise对象。

  1. //用异步async声明的函数
  2. async function go(){
  3. return 1;
  4. }
  5. go(); //通过go()直接调用,会返回Promise对象

image.png

  • 如果async函数是return 一个值,这个值就是Promise对象中resolve的值;
  • 如果async函数中throw一个值,这个值就是Promise对象中reject的值。

举个代码例子:

async函数写法

  1. async function imAsync(num) {
  2. if (num > 0) {
  3. return num // 这里相当于resolve(num)
  4. } else {
  5. throw num+1 // 这里相当于reject(num)
  6. }
  7. }
  8. imAsync(1).then(function (v) {
  9. console.log(v); // 1
  10. });
  11. // 注意这里是catch
  12. imAsync(0).catch(function (v) {
  13. console.log(v); // 1
  14. })

Promise的写法

  1. function imPromise(num) {
  2. return new Promise(function (resolve, reject) {
  3. if (num > 0) {
  4. resolve(num);
  5. } else {
  6. reject(num+1);
  7. }
  8. })
  9. }
  10. imPromise(1).then(function (v) {
  11. console.log(v); // 1
  12. })
  13. imPromise(0).then(function (v) {
  14. console.log(v); // 1
  15. })

二、await

MDN上对await的定义

  1. An async function can contain an await expression, that pauses the execution of the async
  2. function and watis for the passed Promise's resolution, and then resumes the async
  3. function's execution and returns the resolved value.

“await会暂停当前async函数的执行,等待后面的Promise的计算结果返回以后再继续执行当前的async函数。”

所以我们单纯的await setTimeout(..)或者await function xxx是不行的,await后面只能是Promise,它等待的只能是Promise,所以await等待的不是所有异步操作,等待的只能是Promise。
**
并且await必须在async function里面才合法,await is only vaild in async function!

总结await注意点

  1. 1.await必须在async函数里面
  2. 2.await后面修饰的必须是async函数,也就是后面必须是Promise对象

三、async/await要解决的问题

“async/await是为了简化多个Promise的同步操作,就像Promise要解决层层嵌套的回调函数的问题一样
所以async/await就是要完善Promise还不够完美的地方,是在Promise的基础上进行改进的,因此也很好理解为什么await只能“等待”Promise对象。

3-1 回调地狱

async/await是在Promise之后产生的,它和Promise诞生的目的都是为了解决“回调地狱”

async/await - 图2

3-2 Promise改进后

async/await - 图3

3-3 async/await改进后

async/await - 图4

四、应用:小程序搜索

场景:使用的是网易云的接口,发两次请求
第一次请求:搜索框输入关键字,通过下面url发送http请求
https://music.aityp.com/search?keywords=xxxx;

第二次请求:根据第一请求的结果,获取歌曲id,然后发送第二次http请求,请求的url如下:
https://music.aityp.com/playlist/detail?id=第一次请求结果.id;

实现效果如下:
async.gif

4-1 封装http,暴露需要用的接口

  1. var baseUrl = "https://music.aityp.com/"
  2. function HTTP(url,data){
  3. return new Promise((resolve,reject)=>{
  4. wx.request({
  5. url: baseUrl+url,
  6. data,
  7. header: {'content-type':'application/json'},
  8. method: 'GET',
  9. dataType: 'json',
  10. responseType: 'text',
  11. success: (res)=>{
  12. resolve(res.data)
  13. },
  14. fail: (err)=>{
  15. reject(err)
  16. }
  17. });
  18. })
  19. }
  20. /* 暴露需要用到的接口,外部调用只需要传data里的参数 */
  21. module.exports = {
  22. getSearch: (keywords) => {
  23. return HTTP("search", { keywords })
  24. },
  25. getDetail: (ids) => {
  26. return HTTP("song/detail", { ids })
  27. }
  28. }

4-2 引用接口

在需要引用的接口的页面的js里require暴露的接口,如下图这样
image.png

这里需要在事件驱动函数前加上async,因为await只有在async function内才合法

image.png

在使用请求的前面加上await可以暂停当前async函数的执行,等待它后面的async函数的计算结果返回以后才会继续执行当前的async函数。

就以这里发送第二次请求为例:在http.getDetail前加await效果就是,程序到我这了,停一下,等待getDetail请求执行完了,再继续执行后面的语句,后面再在for循环里面不断重复这样的操作,于是实现了同步的效果。