前端 JS 经典:Promise 详解

1. Promise 由来

在以前我们实现异步是用的回调函数,当一个异步请求需要依赖上一个异步请求返回的结果的时候,就会形成如下这种的调用结构。

请求1(function (结果1) {
  请求2(function (结果2) {
    请求3(function(结果3)) {
      请求4(function(结果4) {})
    }
  });
});

这种结构看着很杂乱且不易维护,被我们亲切的叫做 “回调地狱”。为了解决回调地狱的问题,Promise 就诞生了。

Promise 诞生的使命:优雅的去表示异步回调

2. Promise 基础概念

2.1 创建 promise 实例

Promise 是一个构造函数,所以我们在调用一个 Promsie 的时候,要用 new Promsie 的方式去调用。

const ps = new Promise();

new Promise 接受一个函数类型的参数。这个函数又接收两个参数 resolvereject,分别对映成功回调和失败回调。Promise 内部有 3 种状态 pending(进行时)fulfilled(已成功)rejected(已失败)。且这三种状态是不可逆的,只能由 pending 到 fulfilled,pending 到 rejected。resolve 使 promise 状态由 pending 到 fulfilled,reject 使 promise 状态由 pending 到 rejected。

const ps = new Promise(function () {});

 

const ps = new Promise(function (resolve, reject) {
  let number = 10;
  if (number >= 10) {
    resolve(number);
  } else {
    reject("number 小于10");
  }
});

 

2.2 实例方法

为了更好的控制下一步执行,又诞生了三个实例方法 then、catch、finally

2.2.1 then 方法

then 方法一般接受两个参数 resolve、reject。分别对应成功时的回调和失败时的回调。

成功状态的 promise 实例
const ps1 = new Promise(function (resolve, reject) {
  let number = 10;
  if (number >= 10) {
    resolve(number);
  } else {
    reject("number 小于10");
  }
});

ps1.then(function (res) {
  console.log(res);
});

失败状态的 promise 实例
const ps2 = new Promise(function (resolve, reject) {
  let number = 9;
  if (number >= 10) {
    resolve(number);
  } else {
    reject("number 小于10");
  }
});

ps2.then(
  function (res) {},
  function (err) {
    console.log(err);
  }
);

2.2.2 catch 方法

then 方法支持链式调用,then 的执行严重依赖上一步的结果,上一步如果没有结果,那么下一步就不会执行。但是每一步都写 reject 特别麻烦,所以诞生了 catch,then 就可以省略 reject 方法,reject 方法就交给 catch 执行,同时 catch 还可以捕获执行 resolve 的异常。

const ps2 = new Promise(function (resolve, reject) {
  let number = 9;
  if (number >= 10) {
    resolve(number);
  } else {
    reject("number 小于10");
  }
});

ps2
  .then(function (res) {})
  .catch(function (err) {
    console.log(err);
  });

2.2.3 finally 方法

有的时候,无论成功还是失败都需要执行一些操作,就诞生了 finally。我们可以在这做一些清理工作。

const ps2 = new Promise(function (resolve, reject) {
  let number = 9;
  if (number >= 10) {
    resolve(number);
  } else {
    reject("number 小于10");
  }
});

ps2
  .then(function (res) {})
  .catch(function (err) {
    console.log(err);
  })
  .finally(function () {
    console.log("end");
  });

2.2.4 then 的链式调用

因为 then 方法支持链式调用,所以我们需要知道使用 then 方法会有什么效果。只要调用 promise 实例的 then 方法一定产生一个新的 promise,这个 promise 的状态由里面的函数决定。函数什么时候有结果,这个新 promise 状态什么时候由 pending 转 fulfilled。catch 和 finally 同理。

const ps = new Promise(function (resolve, reject) {
  let number = 10;
  if (number >= 10) {
    resolve(number);
  } else {
    reject("number 小于10");
  }
});

ps.then(function (res) {
  return res * 10;
})
  .then(function (res) {
    return res + 2;
  })
  .then(function (res) {
    if (res > 100) {
      console.log(res);
    } else {
      console.log("最后结果小于100");
    }
  });

3. Promise 原型方法

为了满足更多的业务需要,又诞生了 6 个原型方法 Promise.all()、Promise.allSettled()、Promise.any()、Promise.race()、Promise.reject()、Promise.resolve()。且都会返回一个确定状态的 Promsie 对象。

统一使用两个成功异步 ps1、ps2。两个失败异步 ps3、ps4。作为测试用例。如下:

const ps1 = new Promise(function (resolve, reject) {
  setTimeout(() => {
    resolve("成功结果1");
  }, 1000);
});

const ps2 = new Promise(function (resolve, reject) {
  setTimeout(() => {
    resolve("成功结果2");
  }, 2000);
});

const ps3 = new Promise(function (resolve, reject) {
  setTimeout(() => {
    reject("失败结果1");
  }, 3000);
});

const ps4 = new Promise(function (resolve, reject) {
  setTimeout(() => {
    reject("失败结果2");
  }, 2000);
});

3.1 Promise.all()

通过数组的形式传入异步操作,所有的异步执行都成功,才执行成功,如果有一个失败了,就执行失败。例子如下:

都成功,执行 then 方法,成功返回结果,通过 res 以数组的方式返回

Promise.all([ps1, ps2])
  .then(function (res) {
    console.log("都成功", res);
  })
  .catch(function (err) {
    console.log(err);
  });

按传入顺序执行,如果有一个异步执行失败,中断其他异步操作,执行 catch 方法,通过 err 返回失败结果

Promise.all([ps1, ps2, ps3, ps4])
  .then(function (res) {
    console.log("都成功", res);
  })
  .catch(function (err) {
    console.log("执行失败", err);
  });

3.2 Promise.allSettled()

所有执行都有结果了就执行,无论成功还是失败

Promise.allSettled([ps1, ps2, ps3, ps4]).then(function (res) {
  console.log("都返回结果", res);
});

3.3 Promise.any()

任意异步成功了就执行

Promise.any([ps1, ps2, ps3, ps4]).then(function (res) {
  console.log("任意成功", res);
});

3.4 Promise.race()

任意异步成功或失败就执行。

Promise.race([ps1, ps2, ps3, ps4]).then(function (res) {
  console.log("任意成功或失败", res);
});

3.5 Promise.reject()

返回一个状态为 rejected 的 Promise 对象

3.6 Promise.resolve()

会接收 4 种类型的参数:promise 实例 、具有 then 方法的对象、没有 then 方法的对象、不传参

当参数是一个 Promise 实例时,直接返回这个实例。

Promise.resolve(ps1);

 当参数是一个具有 then 方法的对象时,将这个对象转为 Promise 对象,并立即执行对象的 then 方法

let obj = {
  name: "yqcoder",
  then(resolve) {
    resolve(this.name);
  },
};

Promise.resolve(obj);

当参数是一个没有 then 方法的对象,或者参数不是对象时,就会返回状态为 fulfilled 的新的 Promise 对象,并将参数传入下一个 then。

let obj = {
  name: "yqcoder",
};

let ps = Promise.resolve(obj);

ps.then(function (res) {
  console.log("结果", res);
});

 

当不带任何参数时,就会返回一个状态为 fulfilled 的 Promise 对象

Promise.resolve();

 

前端面试中,Promise.all() 是一个常见的问题。它是一个用于处理多个 Promise 对象的方法,返回一个新的 Promise 对象。根据引用所述,Promise.all() 方法接收一个 promise 的 iterable 类型的输入(例如数组),并且只返回一个 Promise 实例。当所有输入的 promise 都成功执行时,Promise.all() 返回的 Promise 对象的 resolve 回调会传递一个包含所有 promise 结果的数组。如果输入的 promise 中有任何一个失败或者输入不合法的 promisePromise.all() 返回的 Promise 对象的 reject 回调会立即抛出错误,并且 reject 的是第一个抛出的错误信息[^2]。 以下是一个示例,演示了如何使用 Promise.all() 方法: ```javascript const promise1 = Promise.resolve(3); const promise2 = 42; const promise3 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'foo'); }); Promise.all([promise1, promise2, promise3]) .then(values => { console.log(values); // 输出:[3, 42, 'foo'] }) .catch(error => { console.error(error); // 如果有任何一个 promise 失败,会立即抛出错误 }); ``` 在上面的示例中,我们创建了三个 Promise 对象:promise1、promise2 和 promise3。promise1 是一个已经解决的 Promisepromise2 是一个普通的值,promise3 是一个在 100 毫秒后解决的 Promise。我们将这三个 Promise 对象作为参数传递给 Promise.all() 方法。当所有的 Promise 都成功执行时,Promise.all() 返回的 Promise 对象的 resolve 回调会传递一个包含所有 promise 结果的数组。在这个示例中,我们通过 then() 方法获取到了这个数组,并将其打印出来。如果有任何一个 Promise 失败,Promise.all() 返回的 Promise 对象的 reject 回调会立即抛出错误,并且 reject 的是第一个抛出的错误信息。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yqcoder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值