深入浅出Promise---解决异步编程的核心

97 阅读18分钟

1.Promise介绍

Promise是异步编程的一种解决方案,它的构造函数是同步执行的,then 方法是异步执行的,所以Promise创建后里面的函数会立即执行,构造函数中的resolve和reject只有第一次执行有效,,也就是说Promise状态一旦改变就不能再变

Promise作用

promise主要是用来解决回调地狱的问题,通过使用.then来使得代码成链式调用,方便维护和使用。.then中的回调函数属于异步任务中的微任务

**回调地狱(callback hell)**是一种在前端开发中常见的代码结构,指的是在处理异步操作时,多个异步操作相互依赖,导致代码变得难以维护和理解。

回调地狱通常是由于在处理异步操作时,使用嵌套的回调函数导致的。例如,下面是一个简单的回调地狱示例:

asyncFunction1(param1, (err1, result1) => {
if (err1) {
 console.error(err1);
} else {
 asyncFunction2(result1, (err2, result2) => {
   if (err2) {
     console.error(err2);
   } else {
     asyncFunction3(result2, (err3, result3) => {
       if (err3) {
         console.error(err3);
       } else {
         console.log(result3);
       }
     });
   }
 });
}
});

在这个示例中,我们使用了三个异步函数asyncFunction1、asyncFunction2和asyncFunction3,它们之间存在依赖关系。为了处理这些依赖关系,我们使用了嵌套的回调函数。这种代码结构不仅难以维护和理解,而且容易出错。

为了解决回调地狱问题,可以使用一些方法,如Promise、async/await等。Promise是一种封装异步操作的模式,可以将异步操作封装成一个Promise对象,从而避免使用嵌套的回调函数。async/await是一种更简洁的异步编程方式,可以方便地处理异步操作之间的依赖关系。

总之,回调地狱是一种在前端开发中常见的代码结构,指的是在处理异步操作时,多个异步操作相互依赖,导致代码变得难以维护和理解。为了解决回调地狱问题,可以使用Promise、async/await等方法。

2.Promise状态

promise对象仅有三种状态

  • pedding =>初始状态:调用promise时,一开始就呈现出等待状态,遇到resolve或者reject之前,都处于这个状态,且可以改变,但如果确定了状态(fulfilled/reject),则结果将永远不变,不能再次修改
  • fulfilled =>成功状态:在执行了resolve后,promise则会从pedding变成fulfilled,后续会进入.then 的回调函数中,在回调函数的第一个参数函数中可以获取到值
  • rejected =>失败状态:在执行了reject后,promise状态会变成rejectedrejected函数传递的参数,可以在.then的第二个参数函数中获取的到,或者是在.catch获取到,但是如果程序上的错误,得通过.catch函数去拿到失败消息,在.then中是获取不了的

promise流程图转存失败,建议直接上传图片文件

3.Promise的用法

3.1.Promise构造函数

通过Promise构造函数来创建一个Promise的实例对象,语法示例如下:

let pro = new Promise((resolve,reject) => {
    //...添加代码来定义此Promise实例对象的状态
})
  • executor函数:执行器,即(resolve,reject) =>{}
  • resolve函数:内部定义成功时我们定义的函数value => {}
  • reject函数:内部定义失败时我们调用的函数reason => {}

说明:executor会在Promise原型中立即同步调用,而异步操作在excutor中执行

3.2.Promise.prototype.then方法

这就是Promise原型的.then((onResolved,onRejected) =>{})方法,也是Promise异步处理的核心机制,能很好的处理回调地狱的问题

该回调函数有两个参数(函数),一个是用于处理 Promise 解决时的回调函数,另一个是可选的用于处理 Promise 拒绝(rejected)时的回调函数;用于接收promise对应状态的数据。而且**.then的返回值也是个promise对象**,具体看后面返回值详解章节

示例如下:

const p = new Promise((resolve, reject) => {
  resolve("成功");
});
const result = p.then(
  (res) => {
    console.log("----打印:p", res); //----打印:p 成功
   
  },
  (rej) => {
    console.log("----打印:p", rej); //不执行
  }
);
result.then(
  (res) => {
    console.log("----打印:第二次", res); //----打印:第二次 undefined
    console.log("----打印:", result); //----打印: Promise { <fulfilled> } --    
    [PromiseState]]: "fulfilled"[[PromiseResult]]: undefined
 
    //为啥呢?
    //因为第一个then没有给返回的具体值--,所以在第二个.then中,
    //剥离掉promise,拿到的result就是undefined
    //虽然.then返回值是promise,但.then里面的参数,拿到的是promise里面携带的值(通俗表达)
 
  },
  (rej) => {
    console.log("----打印:第二次", rej); //不执行
  }
);
 
//这个是最先打印--所以执行这里的时候,显示还是在pedding状态
console.log("----打印:", result); //----打印: Promise { <pending> } --[PromiseState]]: "fulfilled"[[PromiseResult]]: undefined
 
//若这么写。第二个then函数中拿到值就是6,而不是undefined
 const result = p.then(
   (res) => {
     console.log("----打印:p", res); //----打印:p 成功
     return 6
    },
 );
 result.then(
   (res) => {
     console.log("----打印:第二次", res); //----打印:第二次 6
   },
 );

Tips:注意,如果.then中写了参数不是函数,则会变成promise穿透哦!

const p = new Promise((resolve, reject) => {
resolve("成功");
});
const result = p.then(Promise.resolve("传不过去")); //不是函数
result.then((res) => {
console.log("----打印:", res); //----打印: 成功
});
//相当于这中写法
const result1 = p.then(null); //不是函数
result1.then((res) => {
console.log("----打印:", res); //----打印: 成功
});
//也可以写成链式调用,结果一样的
p.then(null).then((res) => {
console.log("----打印:", res); //----打印: 成功
});
  • onResolved函数:成功的回调函数(value) =>{}
  • onRejected函数:失败的回调函数(reason) =>{}

说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个Promise对象

3.3.Promise.prototype.catch方法

catch(onRejected =>{})方法是 .then(null, rejection).then(undefined, rejection) 的一种别名,于注册在 Promise 对象拒绝(rejected)时的回调函数。同时也可以用来捕获代码异常或者出错:

  1. 像如果promise是一个rejected的状态或者抛出异常或者错误,既可以在.then函数中的第二个参数获取,也可以在.catch中的函数中获取,如果两者同时出现代码中(可以看Promise.reject中的案例哦)。
  2. .then中产生异常能在.catch 或者下一个.then中捕获。.then.catch本质上是没有区别的, 需要分场合使用:一般异常用.catch;拒绝状态用.then
  3. 而且,一旦异常被捕获,则未执行后面中的.then不管多少,都不会执行。一般最好用.catch 在最后去捕获,这样能捕获到上面最先报错的信息
const p = new Promise((resolve, reject) => {
  reject("拒绝");
  console.log("----打印:"); //会输出
  throw new Error("抛出错误"); //这一句改变promise状态,因为状态已经决定了
});
p.catch((error) => {
  console.log(error); // :--拒绝
});

// 另外写法
p.then(
  (res) => {},
  (rej) => {
    console.log("----打印:", rej); //----打印: 拒绝
  }
);

//另外情况
const p1 = new Promise((resolve, reject) => {
  throw new Error("抛出错误");
});

p1.catch((error) => {
  console.log("p1", error); //:Error: 抛出错误
});

//另外情况---2
const p2 = new Promise((resolve, reject) => {
  resolve(11);
});

p2.then((res) => {
  console.log("----打印:", res);
  throw new Error("抛出错误");
})
  //如果没有下面这个.then 则错误就会被catch捕获
  //不提倡这种写法--只是为了证明,then也可以接收到异常
  .then(
    (res) => {},
    (rej) => {
      console.log("----打印:能接到就执行", rej); //----打印:能接到就执行 Error: 抛出错误
    }
  )
  .catch((error) => {
    console.log("catch接到", error); //不执行
  });

//另外的情况3
const p3 = new Promise((resolve, reject) => {
  resolve(11);
});

p3.then((res) => {
  console.log("----打印:", res);
  throw new Error("抛出错误");
})
  //如果没有下面这个.then 则错误就会被catch捕获
  //一般是直接在最后写.catch,而不会这么一层层写reject回调函数,除非特殊业务
  .then(
    (res) => {},
    (rej) => {
      console.log("----打印:rej", rej); //执行
    }
  )
  .then(
    (res) => {},
    (rej) => {
      console.log("----打印:会不会执行"); //不会执行
    }
  )
  .catch((error) => {
    console.log("catch接到", error); //不执行
  });

3.4.Promise.resolve()方法

这是创建Promise静态实例对象的方法,用于快速创建一个成功状态的Promise对象实例,它可以在.then的成功回调中获取resolve的值,继而返回一个成功或失败状态的Promise对象

const p = Promise.resolve("成功");
p.then((res) => {
  console.log("----打印:", res); //----打印: 成功
});
 
//该用法等同于以下
const p1 = new Promise((resolve, reject) => {
  resolve("成功");
});
p1.then((res) => {
  console.log("----打印:p1", res); //----打印:p1 成功
});
 
//后续代码中都会出现类似,或者另外中写法,尝试的时候,不能同时放出来执行

3.5.Promise.reject()方法

这是创建Promise静态实例对象的方法,用于快速创建一个失败状态的Promise对象实例,它可以在.then成功回调中获取resolve的值,继而返回一个成功或失败状态的Promise对象;也可以在catch()中获取

业务中,拒绝状态用.then,异常用.catch

const p = Promise.reject("失败");
p.then(
  (res) => {
    console.log("----打印:", res); //不执行
  },
  (rej) => {
    console.log("----打印:", rej); //----打印: 失败
  }
);
 
//另外写法 
p.then(
  (res) => {
    console.log("----打印:p", res); //不执行
  },
  (rej) => {
    console.log("----打印:p", rej); //----打印:p 失败
  }
).catch((error) => {
  console.log("----打印:catch", error); //不执行
});
 
//另外写法---基本没有吧catch写在第一个
p.catch((error) => {
  console.log("----打印:catch", error); //----打印:catch 失败
}).then(
  (res) => {
    console.log("----打印:p", res); //不执行
  },
  (rej) => {
    console.log("----打印:p", rej); //不执行
  }
);
 
//另外写法
p.then((res) => {
  console.log("----打印:p", res); //不执行
}).catch((error) => {
  console.log("----打印:catch", error); //----打印:catch 失败
});
 
//该用法类似于
const p1 = new Promise((resolve, reject) => {
  reject("失败");
});
p1.then(
  (res) => {
    console.log("----打印:p1", res); //不执行
  },
  (rej) => {
    console.log("----打印:p1", rej); //----打印:p1 失败
  }
);

3.6.Promise.all()方法

Promise.all()接收一个Promise对象的数组作为参数

当这个数组里面的Promise对象,没有出现rejected状态,则会一直等待所有resolve成功后,才执行.then这个回调;如果有一个是rejected状态,则会先执行.all里面的.then中第二个参数的回调函数或者.catch函数,不会等后续跑完在执行

传递给Promise.all()的 Promise并不是一个个的顺序执行的,而是同时开始、并行执行的。

var p1 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    resoleve("p1--3000");
  }, 3000);
});
var p2 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    resoleve("p2--1000");
  }, 1000);
});
var p3 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    console.log("----打印:看看是先执行失败,还是全部执行完再catch");
    resoleve("p3--5000");
  }, 5000);
});
 
//第一情况
 var promiseArr = [p1, p2, p3];
 console.time("promiseArr");
  Promise.all(promiseArr)
    .then((res) => {
      console.log("res", res); //res [ 'p1--3000', 'p2--1000', 'p3--5000' ]
      console.timeEnd("promiseArr"); // promiseArr: 5.020s
    })
    .catch((err) => console.log(err));
 
//另外情况
var p4 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    reject("p4--2000");
  }, 2000);
});
 
var promiseArr = [p1, p2, p3, p4];
console.time("promiseArr");
Promise.all(promiseArr)
  .then((res) => {
    console.log("res", res);
    console.timeEnd("promiseArr");
  })
  .catch((err) => console.log(err)); 
 
//打印顺序
//p4--2000
//输出----打印:看看是先执行失败,还是全部执行完再catch 
 
//解释:p3的输出,比上边catch晚输出因此,如果有失败状态,就会提前结束、去执行all里面的回调函数

3.8.Promise.any()方法

Promise.any()接收一个promise的数组作为参数

只要其中有一个Promise成功执行,就会返回已经成功执行的Promise的结果;若全部为rejected状态,则会到最后的promise执行完,全部的promise返回到异常函数中。

可用于多通道获取数据,谁先获取就执行下一步程序,跳出这个过程。---和all()的相反

var p1 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    resoleve("p1--3000");
  }, 3000);
});
var p2 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    reject("p2--1000");
  }, 1000);
});
var p3 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    console.log("----打印p3");
    resoleve("p3--5000");
  }, 5000);
});
 
var promiseArr = [p1, p2, p3];
console.time("promiseArr");
Promise.any(promiseArr)
  .then((res) => {
    console.log("res", res); //res [ 'p1--3000', 'p2--1000', 'p3--5000' ]
    console.timeEnd("promiseArr"); // promiseArr: 5.020s
  })
  .catch((err) => console.log(err));
 
//输出顺序 --虽然p2已经执行完,但是为rejected状态,而any会返回第一个resolve状态的对象
//   res p1--3000
// promiseArr: 3.009s
// ----打印p3
 
//另外一种情况
var p1 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    reject("p1--3000");
  }, 3000);
});
var p2 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    reject("p2--1000");
  }, 1000);
});
var p3 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    console.log("----打印p3");
    reject("p3--5000");
  }, 5000);
});
 
var promiseArr = [p1, p2, p3];
console.time("promiseArr");
Promise.any(promiseArr)
  .then((res) => {
    console.log("res", res); //res [ 'p1--3000', 'p2--1000', 'p3--5000' ]
    console.timeEnd("promiseArr"); // promiseArr: 5.020s
  })
  .catch((err) => console.log(err));
 
//输出结果   解释--因为p1,2,3都是错误,所以any一直在等有成功的状态,所以知道p3结束后,没有成功的,就走catch那边
// ----打印p3
// [AggregateError: All promises were rejected] {
//   [errors]: [ 'p1--3000', 'p2--1000', 'p3--5000' ]
// }

3.9.Promise.race()方法

方法接收的参数和.all、.any接收的参数一样,接收一个可迭代promise对象的数组,当任何一个promise的状态先确定(拒绝或者成功),则会执行.race中的回调函数,具体根据promise的状态 ---和allSettled效果互斥

var p1 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    console.log("----打印:p1");
    resoleve("p1--3000");
  }, 3000);
});
 
let p2 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    reject("p2--1000");
  }, 1000);
});
 
Promise.race([p1, p2])
  .then((res) => {
    console.log("----打印:res", res);
  })
  .catch((err) => {
    console.log("----打印:err", err);
  });
 
//执行结果
//----打印:err p2--1000
//----打印:p1
 
//另外情况
 
let p3 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    resoleve("p3--500");
  }, 500);
});
 
Promise.race([p1, p2, p3])
  .then((res) => {
    console.log("----打印:res", res);
  })
  .catch((err) => {
    console.log("----打印:err", err);
  });
 
//打印结果
// ----打印:res p3--500
// ----打印:p1

3.10.Promise.allSettled()方法

该方法参数也是和.all相同;顾名思义,这个方法是等所有promise参数确定状态后,才会执行回调函数,不管是成功的状态还是拒绝的状态,都等待全部执行后,并返回一个包含每个 Promise 解决状态的对象数组,每个对象包含两个属性:statusvaluestate表示promise的状态:resolverejectedvalue代表的是promise传递的值。

请注意,Promise.allSettled() 是 ES2020(也称为 ES11)中引入的新方法,需要支持该版本的 JavaScript 运行环境才能使用

var p1 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    console.log("----打印:p1");
    resoleve("p1--3000");
  }, 3000);
});
 
let p2 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    reject("p2--1000");
  }, 1000);
});
 
let p3 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    resoleve("p3--500");
  }, 500);
});
 
let p4 = new Promise((resolve, reject) => {
  throw new Error("抛出错误");
});
 
Promise.allSettled([p1, p2, p3, p4])
  .then((result) => {
    console.log("----打印:result", result);
  })
  .catch((err) => {
    console.log("----打印:", err); //不执行
  });
 
//执行结果
// ----打印:p1
// ----打印:result [
//   { status: 'fulfilled', value: 'p1--3000' },
//   { status: 'rejected', reason: 'p2--1000' },
//   { status: 'fulfilled', value: 'p3--500' },
//   {
//     status: 'rejected',
//     reason: Error: 抛出错误
//   }
// ]

3.11.Promise.finally()方法

Promise.finally()方法的回调函数不接受任何参数 这表明,finally()方法里面的操作,应该是与Promise状态无关的,无论 Promise 的状态如何,onFinally 回调都会被执行。它不接收任何参数,也没有返回值。这意味着它主要用于清理和最终处理逻辑,而不关心 Promise 的解决结果或拒绝原因。

var p1 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    resoleve("p1--3000");
  }, 3000);
});
 
p1.then((res) => {
  console.log("----打印:", res);
}).finally(() => {
  console.log("----打印:调用了");
});
 
// //执行结果
// // ----打印: p1--3000
// // ----打印:调用了
let p2 = new Promise((resoleve, reject) => {
  setTimeout(() => {
    reject("p2--1000");
  }, 1000);
});
 
p2.then((res) => {})
  .catch((err) => {
    console.log("----打印:", err);
  })
  .finally(() => {
    console.log("----打印:也调用了");
  });
 
//执行结果
//   ----打印: p2--1000
// ----打印:也调用了

4.Promise的返回值

4.1.new Promise()返回值

返回值是一个promise对象

对象中的状态和值,根据new Promise(() => { })中同步代码的逻辑决定实例化返回的Promise对象状态

let resolveP = new Promise((resolve, resject) => {
  resolve("success");
});
console.log("----打印:", resolveP);
//执行结果
//----打印: Promise {<fulfilled>: 'success'}
let rejectP = new Promise((resolve, resject) => {
  resject("rejected");
});
console.log("----打印:", rejectP);
 
//执行结果
// Promise {<rejected>: 'rejected'}

4.2.promise.then()返回值

情况一.then()回调中无return值或return简单数据类型

  • return值:返回值为undefined成功状态的Promise对象
  • return简单数据类型值:返回值为【简单数据类型的数据】的成功状态的Promise对象
let p = new Promise((resoleve, reject) => {
  setTimeout(() => {
    resoleve("返回值");
  }, 1000);
});
 
const backP = p.then((res) => {
  console.log("----打印:res", res);
});
const finallyBackP = backP.then((res) => {
  return "又有数据";
});
setTimeout(() => {
  console.log("----打印:backP", backP);
}, 2000);
setTimeout(() => {
  console.log("----打印:finallyBackPP", finallyBackP);
}, 3000);
 
//执行结果
// ----打印:res 返回值
// ----打印:backP Promise {<fulfilled>: undefined}
//----打印:finallyBackPP Promise {<fulfilled>: '又有数据'}

情况二.then()回调中return实例的Promise对象

返回的Promise对象与return的实例化Promise对象的状态和值一致

let p = new Promise((resoleve, reject) => {
  setTimeout(() => {
    resoleve("返回值");
  }, 1000);
});
 
const backP = p.then((res) => {
  console.log("----打印:", res);
  return Promise.resolve(res + "成功的promise");
});
const finallyBackP = backP.then((res) => {
  console.log("----打印:", res);
  return Promise.reject("最后是失败的promise");
});
setTimeout(() => {
  console.log("----打印:backP", backP);
}, 2000);
setTimeout(() => {
  console.log("----打印:finallyBackPP", finallyBackP);
}, 3000);
 
//执行结果
// ----打印: 返回值
// ----打印: 返回值成功的promise
// ----打印:backP Promise {<fulfilled>: '返回值成功的promise'}
// ----打印:finallyBackPP Promise {<rejected>: '最后是失败的promise'}

情况三.then()回调中抛出异常错误

返回状态为失败,值为抛出的错误的Promise对象

let p = new Promise((resoleve, reject) => {
  setTimeout(() => {
    resoleve("返回值");
  }, 1000);
});
 
const backP = p.then((res) => {
  console.log("----打印:", res);
  throw new Error("程序错误");
});
 
setTimeout(() => {
  console.log("----打印:backP", backP);
}, 2000);
 
//打印结果
//----打印: 返回值
// ----打印:backP Promise {<rejected>: Error: 程序错误
 
 
//另外情况
//一般业务中,promise最后都会用.catch兜住,防止程序出错,这种写法的返回值,则跟情况一相同
 
let p = new Promise((resoleve, reject) => {
  setTimeout(() => {
    resoleve("返回值");
  }, 1000);
});
 
const backP = p
  .then((res) => {
    console.log("----打印:", res);
    throw new Error("程序错误");
  })
  .catch((error) => {
    console.log("----打印:", error);
  });
 
setTimeout(() => {
  console.log("----打印:backP", backP);
}, 2000);
 
//打印结果
 
//----打印: 返回值
//----打印: Error: 程序错误  at <anonymous>:10:11
// ----打印:backP Promise {<fulfilled>: undefined}

5.asyncawait

5.1.定义

async 是异步的意思,await则可以理解为 async wait

  • async就是用来声明一个异步方法
  • await是用来等待异步方法执行

async作为一个关键字放在函数前面,表示该函数是一个异步函数,异步函数意味着该函数的执行不会阻塞后面代码的执行;而 await 用于等待一个异步方法执行完成。

await 等待一个 Promise 对象,如果 Promise的状态变成了 resolve 或者 rejcet,那么 async函数会恢复执行。并会阻塞该函数内后面的代码。

使用 async/await 可以实现用同步代码的风格来编写异步代码,这是因为 async/await 的基础技术使用了生成器Promise,生成器是协程的实现,利用生成器能实现生成器函数的暂停和恢复。是为了优化 .then 链而开发出来的。

5.2.async/await 出现的原因

Promise 的编程模型依然充斥着大量的 then 方法,虽然解决了回调地狱的问题,但是在语义方面依然存在缺陷,代码中充斥着大量的 then 函数,这就是 async/await 出现的原因。async/await 让代码更少,更简洁。

5.3.关于async

async function 声明创建一个绑定到给定名称的新异步函数。函数体内允许使用 await 关键字,这使得我们可以更简洁地编写基于 promise 的异步代码,并且避免了显式地配置 promise 链的需要。

语法:

async function (param1,param2,...){
    ...
}

描述

  • async function 声明创建一个 AsyncFunction 对象

  • 返回值每次调用异步函数时,都会返回一个新的 Promise 对象,该对象将会被解决为异步函数的返回值,或者被拒绝为异步函数中未捕获的异常。

    备注

    即使异步函数的返回值看起来像是被包装在了一个 Promise.resolve 中,但它们不是等价的。

    如果给定的值是一个 promise,异步函数会返回一个不同的引用,而 Promise.resolve 会返回相同的引用,

    当你想要检查一个 promise 和一个异步函数的返回值是否等价时,这可能是一个麻烦。

    const p = new Promise((res, rej) => {
    res(1);
    });
    
    async function asyncReturn() {
    return p;
    }
    
    function basicReturn() {
    return Promise.resolve(p);
    }
    
    console.log(p === basicReturn()); // true
    console.log(p === asyncReturn()); // false
    
  • 异步函数可以包含零个或者多个 await 表达式。await 表达式通过暂停执行使返回 promise 的函数表现得像同步函数一样,直到返回的 promise 被兑现或拒绝。返回的 promise 的解决值会被当作该 await 表达式的返回值。使用 async/await 关键字就可以使用普通的 try/catch 代码块捕获异步代码中的错误。

5.4.关于await

await 操作符用于等待一个 Promise 兑现并获取它兑现之后的值。它只能在async异步函数或者模块顶层中使用。

语法:

await expression; //要等待的 Promise 实例,Thenable 对象,或任意类型的值。

返回值:

返回从 Promise 实例或 thenable 对象取得的处理结果,即PromiseResult。如果等待的值不符合 thenable,则返回表达式本身的值。

await 通常用于拆开 promise 的包装,即PromiseResult。使用方法是传递一个 Promise 作为 expression。使用 await 总会暂停当前异步函数的执行,在该 Promise 敲定(settled,指兑现或拒绝)后继续执行。函数的执行恢复(resume)时,await 表达式的值已经变成了 Promise 兑现的值,即PromiseResult

await 总会同步地对表达式求值并处理,处理的行为与 Promise.resolve() 一致,不属于原生 Promise 的值全都会被隐式地转换为 Promise 实例后等待。处理的规则为,若表达式:

  • 是一个原生 Promise(原生Promise 的实例或其派生类的实例,且满足 expression.constructor === Promise),会被直接用于等待,等待由原生代码实现,该对象的 then() 不会被调用。
  • 是 thenable 对象(包括非原生的 Promise 实例、polyfill、Proxy、派生类等),会构造一个新 Promise 用于等待,构造时会调用该对象的 then() 方法。
  • 不是 thenable 对象,会被包装进一个已兑现的 Promise 用于等待,其结果就是表达式的值。

异常:

拒绝(reject)的原因会被作为异常抛出。

若该 Promise 被拒绝(rejected),await 表达式会把拒绝的原因(reason)抛出。当前函数(await 所在的函数)会出现在抛出的错误的栈追踪(stack trace),否则当前函数就不会在栈追踪出现。