【JS】Promise和async/await函数

187 阅读3分钟

参考

2020 年前端面试复习必读精选文章

Promise

介绍

Promise是 ES6 中新增的一种异步编程的解决方案。从语法上来讲,其是一个构造函数,用于创建一个表示“承诺”的实例。具体见下:

以下假设 ajax 是一个异步操作,接受一个参数作为执行成功的回调函数。ajax 执行过程中可能抛出错误。

new Promise((resolve, reject) => {
  try {
    ajax((val) => {
      resolve(val);
    });
  } catch (err) {
    reject(err);
  }
});

其执行流程见下:

  1. 实例创建后,其状态初始为pending(进行中),随后参数函数会立即执行。
  2. 碰到resolve后,其状态会变为fulfilled(已完成);碰到reject或者抛出错误后,其状态会变为rejected(已拒绝)。
  3. 继续执行,直到所有代码执行完毕。
  4. 根据实例状态,执行对应的回调。

这说明,实例的状态最终只可能是fulfilledrejected两者之一,且没有变回pending的可能。创建Promise实例,就像是抛出一枚硬币,结果要么是正面朝上、要么是反面朝上。

实例方法

// 【then】
// 参数1 - 实例状态改变至fulfilled的回调函数
// 参数2 - 实例状态改变至rejected的回调函数(可选)
// 返回值 - Promise.resolve(执行的回调函数的返回值)
p.then(
  (val) => {},
  (err) => {}
).then(
  (val) => {},
  (err) => {}
);

// 【catch】
// err具有冒泡性质,会一直向后传递,直到被捕获,
// 所以在最后写上catch,能保证捕获到错误
p.then((val) => {})
  .then((val) => {})
  .catch((err) => {});
// 等同于:
p.then((val) => {})
  .then((val) => {})
  .then((null, err) => {});

// 【finally】
// 无论最后状态如何,都会执行finally中的回调,
// 会自动将值或错误传递下去
p.then((val) => {})
  .catch((err) => {})
  .finally(() => {});
// 等同于
p.then((val) => {})
  .then((null, err) => {})
  .then(
    (val) => {
      // 代码
      return val;
    },
    (err) => {
      // 代码
      throw err;
    }
  );

静态方法

// 【all】
// 将多个实例包装成一个新实例,分为2种情况:
// 1.在所有实例的状态都变为fulfilled后,
//   其状态变为fulfilled,返回值为所有实例的返回值组成的数组
// 2.在任一实例的状态变为rejected后,
//   其状态变为rejected,返回值为那个实例的返回值
Promise.all([p1, p2, p3]);

// 【any】
// 将多个实例包装成一个新实例,分为2种情况:
// 1.在任一实例的状态变为fulfilled后,
//   其状态变为fulfilled,返回值为那个实例的返回值
// 2.在所有实例的状态变为rejected后,
//   其状态变为rejected,返回值为所有实例的返回值组成的数组
Promise.any([p1, p2, p3]);

// 【allSettled】
// 将多个实例包装成一个新实例:
// 在所有实例改变状态后,
// 其状态变为fulfilled,返回值为所有实例的返回值组成的数组
Promise.allSettled([p1, p2, p3]);

// 【race】
// 将多个实例包装成一个新实例:
// 在任一实例改变状态后,
// 其状态和返回值都同那个实例
Promise.race([p1, p2, p3]);

// 【resolve】
// 将参数转变为Promise实例,分为4种情况:
// 1.参数是一个Promise实例,
//   则原封不动的返回
// 2.参数是包含then方法的对象,
//   则返回new Promise(obj.then)
// 3.参数是不包含then方法的对象,或者不是对象,
//   则返回new Promise((resolve)=>{resolve(obj)})
// 4.无参数,
//   则返回new Promise((resolve)=>{resolve(undefined)})
Promise.resolve(obj);

// 【reject】
// 将参数转变为Promise实例:
// 返回new Promise((resolve,reject)=>{reject(obj)})
Promise.reject(obj);

应用

可以将图片的加载写成一个Promise,一旦加载完成,Promise的状态就发生变化具体见下:

const preloadImage = (path) => {
  return new Promise((resolve, reject) => {
    const image = new Image();
    image.onload = resolve;
    image.onerror = reject;
    image.src = path;
  });
};

也可以利用Promise实现 AJAX 操作。具体见下:

const getJSON = (url) => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onreadystatechange = function () {
      if (this.readyState === 4 && this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    xhr.responseType = "json";
    xhr.setRequestHeader("Accept", "application/json");
    xhr.send();
  });
};

getJSON("/posts.json").then(
  function (data) {
    console.log("Contents:", data);
  },
  function (err) {
    console.error("Error:", err);
  }
);

原理

其原理请见此文

async/await 函数

async/await 函数实际上是利用PromiseGenerator函数实现的另一种异步解决方案。

具体请见此文