hzzzzzzzq / Blog

这是我记录博客的地方,希望能多写一些技术博客,JS、ES、React、Vue等
14 stars 0 forks source link

ES 6 系列 - 9. 三种异步之Promise对象 #10

Open hzzzzzzzq opened 2 years ago

hzzzzzzzq commented 2 years ago

Promise 对象

含义

Promise 是异步编程的一种解决方案,在 Promise 之前,采用的是回调函数和事件,但是会存在一些问题,像回调地狱。而在 ES6 中,提供了 Promise 对象。

Promise 简单来讲,其实就是一个容器,用来存储异步事件(例如网络请求等)。

语法上来说,Promise 是一个对象,可以获取异步操作的消息。

主要特点

主要缺陷

基本用法

这里一般需要进行异步操作,但是为了学习方便,我们直接同步进行了。 Promise 构造函数接受一个函数作为参数,该函数的参数为 resolverejectresolvereject 是两个函数,有 JS 引擎提供,不需要自己部署。 resolve 函数作用是将 Promise 的状态从 pending 变为 resolved,并且将操作结果作为参数传递出去。 reject 函数作用是将 Promise 的状态从 pending 变为 rejected,并且将错误信息传递出去。 Promise 生成实例之后,可以调用 then 方法,其中包含两个函数参数。第一个函数包含 resolved 状态的结果,第二个包含 rejected 状态结果。两个函数都是可选参数。

我们将 flag 比做异步操作,true 表示异步成功,false 表示异步失败。

const promise = new Promise((resolve, reject) => {
  let flag = true;
  if (flag) {
    resolve('操作成功');
  } else {
    reject('操作失败');
  }
});
promise.then(
  (value) => {
    console.log('value = ', value);
  },
  (error) => {
    console.log('error = ', error);
  }
);

从上面的代码来看,flagtrue 时,会打印 value = 操作成功,为 false 时,打印 error = 操作失败

我们来看看 then 的异步。 在 Promise 创建时,就会立即执行,而 then 会在当前脚本所有同步任务执行完才会执行。

const promise = new Promise((resolve, reject) => {
  console.log('1');
  resolve('2');
});
promise.then((val) => {
  console.log(val);
});
console.log('3');
// '1'
// '3'
// '2'

实例方法

Promise.prototype.then()

Promise.prototype.then() 方法作用是为 Promise 实例添加状态改变时的回调函数。 then 方法的第一个参数是 resolved 状态的回调函数,第二个参数是 rejected 状态的回调函数,它们都是可选的值,不一定必须传入。

then 方法返回的是一个新的 Promise 实例,所以可以采用链式写法。

const promise = new Promise((resolve, reject) => {
  resolve('1');
});
promise
  .then((val) => {
    return val;
  })
  .then((val) => {
    console.log(val);
  });
// '1'

Promise.prototype.catch()

Promise.prototype.catch() 方法就是在 then 方法时 reject 的情况,用于发生错误时的回调函数。

const promise = new Promise((resolve, reject) => {
  reject('1');
});
promise.catch((error) => {
  console.log(error);
});
// '1'

如果在 Promise 中报错,进行错误抛出,状态会变为 rejected,就会调用 catch() 方法指定的回调函数,然后在其中处理错误。

当然,如果在运行过程中,抛出错误,也会被 catch 捕获。

const promise = new Promise((resolve, reject) => {
  throw new Error('Error');
});
promise.catch((error) => {
  console.log(error);
});
// 'Error'

Promise.prototype.finally()

Promise.prototype.finally() 方法不管 Promise 对象最后状态如何,都会进行执行。

const promise1 = new Promise((resolve, reject) => {
  resolve('成功');
});
promise1.finally(() => {
  console.log('执行finally');
});
// 执行finally
const promise2 = new Promise((resolve, reject) => {
  reject('失败');
});
promise2.finally(() => {
  console.log('执行finally');
});
// 执行finally

Promise 类方法

Promise.all()

Promise.all() 方法可以将多个 Promise 实例,包装成一个新的 Promise 实例。

const promise1 = new Promise((resolve, reject) => {
  resolve('1');
});
const promise2 = new Promise((resolve, reject) => {
  resolve('2');
});
const promise3 = new Promise((resolve, reject) => {
  resolve('3');
});
const promise = Promise.all([promise1, promise2, promise3]);

promise.then((val) => {
  console.log(val);
});
// ['1', '2', '3']
// 我们将上面的代码其中一个 resolve 修改为 reject('1')
const promise3 = new Promise((resolve, reject) => {
  reject('3');
});
const promise = Promise.all([promise1, promise2, promise3]);

promise.then(
  (val) => {
    console.log(val);
  },
  (error) => {
    console.log(error); // 3
  }
);

Promise.race()

Promise.race() 方法同样是将多个实例包装为一个新的 Promise 实例。

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('1');
  }, 1000);
});
const promise2 = new Promise((resolve, reject) => {
  resolve('2');
});
const promise3 = new Promise((resolve, reject) => {
  resolve('3');
});
const promise = Promise.race([promise1, promise2, promise3]);

promise.then((val) => {
  console.log(val);
});
// 2

我们在第一个使用了 setTimeout,进行延迟,所以会是第二个的状态先改变,输出第二个的值。

Promsie.allSettled()

Promise.allSettled() 方法,用来确定一组异步操作是否都结束了。 数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象,只有数组中的 Promsie 对象状态都发生改变时,返回的 Promise 对象才发生改变。 返回的值会接收到一个数组作为参数,该数组的每一个成员对应前面数组的每个 Promise 对象。

const promise1 = new Promise((resolve, reject) => {
  reject('1');
});
const promise2 = new Promise((resolve, reject) => {
  resolve('2');
});
const promise3 = new Promise((resolve, reject) => {
  reject('3');
});
const promise = Promise.allSettled([promise1, promise2, promise3]);
promise.then(
  (val) => {
    console.log(val);
  },
  (error) => {
    console.log(error);
  }
);
// [
//   {
//     status: 'rejected',
//     reason: '1',
//   },
//   {
//     status: 'fulfilled',
//     value: '2',
//   },
//   {
//     status: 'rejected',
//     reason: '3',
//   },
// ];

数组成员对象的 status 属性的值只可能是 fulfilledrejected,用来区别异步操作结果是成功(fulfilled)还是失败(rejected)。 如果是成功是会有 value 属性,记录成功值,如果失败,会有 reason 属性,记录失败原因。

Promise.any()

Promise.any() 方法,将一组 Promise 实例作为参数,包装成一个新的 Promise 实例并返回。

const promise1 = new Promise((resolve, reject) => {
  reject('1');
});
const promise2 = new Promise((resolve, reject) => {
  resolve('2');
});
const promise3 = new Promise((resolve, reject) => {
  reject('error');
});
Promise.any([promise1, promise2, promise3])
  .then((val) => {
    // 只要有一个成功
    console.log(val);
  })
  .catch((error) => {
    console.log(error);
  });
// 2

Promise.resolve()

Promise.resolve() 方法有四种情况。

const promise = Promise.resolve('请求成功');
// 等价于
const promise = new Promise((resolve) => resolve('请求成功'));
const promise = new Promise((resolve) => resolve('请求成功'));
const promise1 = Promise.resolve(promise);
promise1.then((val) => {
  console.log(val);
});
const thenable = {
  then: function (resolve, reject) {
    resolve('成功');
  },
};
const promise = Promise.resolve(thenable);
promise.then((val) => {
  console.log(val);
});
// 成功
const promise = Promise.resolve('成功');

promise.then((val) => {
  console.log(val);
});
// 成功

注意,立即 resolve()Promise 对象,是在本轮[事件循环(event loop)]()的结束时执行。

const promise = Promise.resolve();

promise.then(() => {
  console.log('不带参数');
});
// 事件循环
// 不带参数
console.log('事件循环');

Promise.reject()

Promise.reject() 方法返回一个新 Promise 实例,该实例状态为 rejected

const promise = Promise.reject('出错了的Promise');
// 同价
const promise = new Promise((resolve, reject) => {
  reject('出错了的Promise');
});

promise.then(null, (error) => {
  console.log(error);
});
// 出错了的Promise