✨使用Promise

184 阅读6分钟

什么是Promise?

首先,Promise是ES6新增的一种对象,中文可以叫做期约。他的出现是为了简化异步编程。那么什么是异步编程

什么是异步编程?

异步编程是一种编程的方式

简单来说,当代码的运行过程种出现了一个耗时的操作(如文件读写、网络请求、数据库查询等)的时候,该耗时操作不会使得后续的代码被它所影响,而是继续运行。

举个🌰

比如你的需求是做如下几件事情:

  1. 双击桌面的云原神图标
  2. 排队等待进入游戏(耗时操作,除非你是氪金用户不用排队🤑)
  3. 刷朋友圈

如果是非异步的代码,那么当你做完第一步之后、你就只能傻愣愣地排队等待进入游戏了,你啥也不能做,只能等着。

然后任务2完成之后,你进入了游戏,你才开始刷朋友圈。

但是如果是异步的代码,你就可以在排队等待进入游戏的过程中,利用这个等待的时机去刷一刷朋友圈了,而不是在干等着啥也不干。

所以其实异步的思维才符合我们的直觉。

没有Promise的异步操作麻烦在哪里?为啥就需要Promise来简化?

😎回顾一下:我们说Promise的出现简化了异步操作,而异步操作就是当我遇到一个耗时的操作的时候,我可以先不管他,先执行这个耗时操作后面的操作。

那肯定是原来的异步操作有亿些不太方便的地方了,才来了一个Promise来简化的。

我就没听过谁说过0~5以内的加减法需要简化的。

那么下面就来简单说下没有Promise的异步操作麻烦在哪里?为啥就需要Promise来简化?

这方面不是重点(重点是后面的Promise),简要的说,有下面几个麻烦的地方

  1. ☹️回调地狱(Callback Hell)😭

一个异步操作依赖于另一个异步操作的结果时,我们可能会遇到嵌套的回调函数,这会让代码变得难以阅读和维护

  1. ☹️错误处理困难😭

回调函数嵌套过多时,错误传播和处理会变得非常困难。

  1. ☹️无法链式调用😭

没有.then()方法,man!这谁受得了。

言而总之+总而言之,Promise来了

下面,Promise

启动✨!就是为什么Promise(以及后来的async/await)在JavaScript中变得如此重要的原因。

下面就是Promise的使用了✨✨✨✨✨巨重要

P.S. 如果大家是新手的话,推荐大家在谷歌浏览器的控制台多手敲几遍,很快就熟悉了😎

P.S. 再Promise中,存在三种状态:

  1. 异步操作未完成【pending】【adj. 未决定的】
  2. 异步操作成功【fulfilled】【adj. 满足的】
  3. 异步操作失败【rejected】【adj. 被拒的】 其中,fulfilledrejected两种状态都是resolved【adj. 已解决的】。

大家只要记住,状态的改变只会从pendingfulfilled,或者从pendingrejected

没有其他的状态改变方式了

这个搞懂,就可以看下面的Promise的简单例子了

例子 1:创建和使用一个简单的Promise

代码:

const myFirstPromise = new Promise((resolve, reject) => {
  const success = true;

  if (success) {
    resolve('成功😎');
  } else {
    reject('失败😭');
  }
});

myFirstPromise
  .then(result => {
    console.log(result); // 输出: 成功😎
  })
  .catch(error => {
    console.error(error);
  });

解析:

  1. new Promise 创建一个Promise对象,接受一个函数作为参数,该函数包含两个参数:resolvereject
  2. resolvereject 分别用于表示操作的成功失败
  3. 在示例中,我们用一个布尔值 success 来决定调用 resolve 还是 reject
  4. then 方法注册了一个回调函数,这个回调函数会在Promise被成功解析时执行,并接收解析值。
  5. catch 方法注册了一个回调函数,这个回调函数会在Promise被拒绝时执行,并接收错误信息。

例子 2:链式调用(Chaining Promises)

代码:

const step1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('原'), 1000);
});

step1
  .then(result => {
    console.log(result);
	// 返回一个新的Promise
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve('神'), 1000);
    });
  })
  .then(result => {
    console.log(result);
	// 返回一个新的Promise
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve('启动!'), 1000);
    });
  })
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error(error);
  });

解析: 乍一看很长,其实真挺长的。 但是其实一点都不难,纸老虎(paper tiger)而已。

  1. step1 是一个Promise对象,在1秒钟后解析。
  2. 使用 then 方法处理 step1 的结果,并返回一个新的Promise。
  3. 这个新的Promise在1秒钟后解析,并使用另一个 then 方法处理其结果。
  4. 这种链式调用允许我们将多个异步操作按顺序连接起来,每个操作在前一个操作完成后开始。

例子 3:并行Promise(Promise.all)

建议配合MDN的解释食用

代码:

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('原'), 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('神'), 2000);
});

const promise3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('启动!'), 3000);
});

Promise.all([promise1, promise2, promise3])
  .then(results => {
    console.log(results); // 输出: [原', '神', '启动!']
  })
  .catch(error => {
    console.error(error);
  });

解析:

  1. promise1, promise2, promise3 是三个独立的Promise对象,分别在1秒、2秒和3秒后解析。
  2. Promise.all 方法接收一个Promise数组,当所有Promise都被解析时,返回一个新的Promise,这个新的Promise解析后的值是一个包含所有输入Promise解析值的数组。
  3. 如果其中任何一个Promise被拒绝,Promise.all 返回的Promise也会立即被拒绝,并且拒绝原因是第一个被拒绝的Promise的拒绝原因。

例子 4:Promise.race

老规矩

代码:

const promiseA = new Promise((resolve, reject) => {
  setTimeout(() => resolve('我最快'), 1000);
});

const promiseB = new Promise((resolve, reject) => {
  setTimeout(() => resolve('我第二快'), 2000);
});

const promiseC = new Promise((resolve, reject) => {
  setTimeout(() => resolve('我最慢'), 3000);
});

// 注意,将多个Promise对象放入数组中
Promise.race([promiseA, promiseB, promiseC])
  .then(result => {
    console.log(result); // 输出: 我最快
  })
  .catch(error => {
    console.error(error);
  });

解析:

  1. promiseA, promiseB, promiseC 是三个独立的Promise对象,分别在1秒、2秒和3秒后解析。
  2. Promise.race 方法接收一个Promise数组,当第一个Promise被解析或拒绝时,返回一个新的Promise,这个新的Promise解析值是第一个解析或拒绝的Promise的值。
  3. 在这个例子中,由于 promiseA 最先解析,因此 Promise.race 返回的Promise也会解析,值为 promiseA 的解析值。

最后

本文是对Promise的简单使用。 后续更文计划: 我后续会先写生成器和迭代器的内容,然后再写async和await的内容。