tanxin03/web-knowledge

看完这个,你就懂了Promise的一切

Opened this issue · 0 comments

1.Promise的含义

promise 是前端的一种异步编程的解决方案,比传统的解决方案(回调函数和事件)更合理和更强大。ES6将其写进了语言标准,提供了原声的Promise对象

所谓promise,就是保存一个未来才会结束的事件(通常是异步操作),

  • promise对象的状态不受外界影响。promise对象代表一个异步操作,有三种状态:pending、fulfilled、rejected,只有异步操作的结果,可以决定当前是哪一种状态,其他操作都不能改变这种状态
  • 一但状态改变,就不会再变。promise的状态改变只有两种可能:从pending变为fulfilled和从pending变为rejected
  • promise也有一些缺点。首先,无法取消promise,一但新建他就会立即执行,无法中途取消;其次,如果不设置回调函数,promise内部抛出的错误,不会反应到外部;第三,当处于pending状态时,无法得知目前进展到哪一个阶段

2.基本用法

ES6规定,Promise是一个构造函数,用来生成promise实例

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

promise生成实例后,可以用then方法分别制定resolve状态和reject状态的回调函数

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

3.then()

promise具有then方法。也就是说,then方法定义在原型对象 Promise.prototype上的。它的作用是为了Promise实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是resolve状态的回调,第二个参数是reject状态的回调,他们都是可选的

then方法返回的是一个新的Promise实例(是新的,不是原来的),因此可采用链式写法,即then方法后面再调用另一个then方法

getJSON("/posts.json").then(function(json) {
  return json.post;
}).then(function(post) {
  // ...
});

上面带嘛使用then方法,依次制定了两个回调函数,第一个回调函数执行完成过后,会将返回结果作为参数,传入第二个回调函数。

4.catch()

catch()是.then(null, rejection)或.then(undefined, rejection)的别名,用于制定发生错误时的回调函数

getJSON('/posts.json').then(function(posts) {
  // ...
}).catch(function(error) {
  // 处理 getJSON 和 前一个回调函数运行时发生的错误
  console.log('发生错误!', error);
});
p.then((val) => console.log('fulfilled:', val))
  .catch((err) => console.log('rejected', err));

// 等同于
p.then((val) => console.log('fulfilled:', val))
  .then(null, (err) => console.log("rejected:", err));

5.finally()

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的promise状态到底是fulfilled还是rejected。这表明,finally方法面的操作,应该与状态无关的,不依赖于promise的执行结果
finally本质上是then方法的特例

6.all()

promise.all()方法用于将多个Promise实例,包装成一个新的promise实例

const p = Promise.all([p1,p2,p3])

上面代码中,promise.all()方法接受一个数组作为参数,p1、p2、p3都是promise实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为promise实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有Iterator接口,且返回的每一个成员都是Promise实例

p的状态由p1、p2、p3决定,分成两种情况。

1.只有p1、p2、p3的状态变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数
2.只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数

7.race()

const p = Promise.race([p1, p2, p3]);

上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

8.allSettled()

allSettled()方法接受一组promise实例作为参数,包装成一个新的promise实例。只有等到所有参数实例都返回结果,不管是fulfilled还是reject,实例才会结束

const promises = [
  fetch('/api-1'),
  fetch('/api-2'),
  fetch('/api-3'),
];

await Promise.allSettled(promises);
removeLoadingIndicator();

上面带嘛对服务器发出三个请求,等到三个请求都结束,不管请求成功还是失败,都会返回

9.any()

该方法接受一组promise实例作为参数,包装一个新的promise实例返回。只要参数实力有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成reject状态,包装实例就会变成rejected状态

resolve()

有时需要将现有对象转为Promise对象,promise.resolve()方法就起到这个作用