(JS基础)Promise 对象

·  阅读 534

概述

Promise对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的

Promise对象有三种状态pending(初始状态)、fulfilled(成功状态)、rejected(失败状态)。

Promise对象的状态一旦由pending变为fulfilledrejected无法再更改

Promise对象的状态变为fulfilled后,通过then()方法执行回调函数;状态变为rejected后,通过catch()方法执行回调函数。

在 ES2018 中引入了finally(),表示该Promise执行结束后(无论是"then"还是"catch"导致的结束)都会执行传入finally方法的回调函数,回调函数无参数。


简单示例

创建

通过new运算符可以创建Promise实例,唯一参数是带有 resolvereject两个参数的 executor函数resolvereject函数被调用时,分别将Promise的状态改为fulfilled(完成)或rejected(失败),两个函数都接受一个参数,作为成功(或失败)的信息传递给对应的处理方法(thencatch)。

let p = new Promise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve('resolve');
    } else {
      reject('reject');
    }
  }, 1000);
});复制代码

上述例子中,1 秒后随机把Promise对象的状态改为fulfilled(完成)或rejected(失败)。

处理

被创建的Promise对象会立即执行executor函数,如果我们还需要在该异步函数结束后再做点什么,就需要调用Promise对象的then()catch()finally()方法。(三个方法都会返回一个新的Promise对象,因此能使用"链式操作")

接上例子:

p.then(res => {
  console.log(res);   // 'resolve'
}).catch(err => {
  console.log(err);   // 'reject'
}).finally(()=>{
  console.log('finally');    // 必定执行
});复制代码

可以看出,then()catch()方法传入的是一个回调函数,该回调函数有唯一参数,对应的是resolvereject函数传入的参数。finally()同样是传入一个对调函数,不同的是该回调函数无参数。

几种场景

场景1:多个Promise需要依次执行。(Promise.prototype.then()可以传入另一个Promise对象

const promise1 = new Promise(...);
const promise2 = new Promise(...);
const promise3 = new Promise(...);
// promise1成功执行后再执行promise2,再是promise3
promise1.then(promise2).then(promise3);复制代码

场景2:多个Promise需要都成功。(静态方法:Promise.all()

const promise1 = new Promise(...);
const promise2 = new Promise(...);
const promise3 = new Promise(...);
// promise1/2/3 均成功后再执行 then ( 其中一个失败也不会执行 then )
Promise.all([promise1, promise2, promise3]).then(callback(){...});复制代码

场景3:多个Promise只需要其中一个成功。(静态方法:Promise.race()

const promise1 = new Promise(...);
const promise2 = new Promise(...);
const promise3 = new Promise(...);
// promise1/2/3 任意一个成功后执行 then
Promise.race([promise1, promise2, promise3]).then(callback(){...})
复制代码

Promise.resolve()

Promise.resolve()用于生成一个状态为fulfilledPromise对象。其参数与.prototype.resolve()一致。

let p1 = Promise.resolve('resolve');
// 等效如下代码
let p2 = new Promise((resolve, reject) => {
  resolve('resolve');
});复制代码

Promise.reject()

Promise.reject()用于生成一个状态为rejectedPromise对象。其参数与.prototype.reject()一致。

let p1 = Promise.reject('resolve');
// 等效如下代码
let p2 = new Promise((resolve, reject) => {
  reject('resolve');
});复制代码


继续深入了解

then() 的第二个参数

其实上面的介绍中,完全没有提及then()的第二个参数,因为其作用与catch()方法一致。看下面例子:

let p = new Promise((resolve, reject) => {
  reject('reject');
})
p.then(res => { }, err => {
  console.log(err);     // 'reject'
});
p.catch(err => {
  console.log(err);     // 'reject'
});
复制代码

不传参的 then()/catch()/finally()

then()/catch()/finally()不传入参数,都会返回与原Promise对象相同(但不相等)的新Promise对象。看如下例子:

// 不传参的"then"
let p1 = Promise.resolve('resolve');
let p2 = p1.then();
p2.then(res => {
  console.log(res);       // 'resolve'
});
console.log(p1 === p2);   // false
// 不传参的"catch"
let p3 = Promise.reject('reject');
let p4 = p3.catch();
p4.catch(res => {
  console.log(res);       // 'reject'
});
console.log(p3 === p4);   // false
// 不传参的"finally"
let p5 = Promise.resolve('resolve');
let p6 = p5.finally();
p6.then(res => {
  console.log(res);       // 'resolve'
});
console.log(p5 === p6);   // false
复制代码

then()/catch()/finally() 的参数是带返回值的回调函数

then()catch()的参数是有返回值的回调函数Athen()catch()返回一个状态为fulfilledPromise对象。新Promise对象的then()方法的回调函数的参数就是回调函数A的返回值。

注意,状态为rejectPromise对象在then()的第一个对调函数返回会导致报错。

注意,finally()的对调函数"return"并不会影响新的Promise对象的then()catch()方法的回调函数的参数值。

如果觉得文字描述有点绕,看下面例子:

// 'resolve'状态被处理后的'return'
Promise.resolve('resolve').then(() => {
  return 'return1'
}).then(res => {
  console.log(res)
});   // 'return1'
// 'reject'状态被处理后的'return'
Promise.reject('resolve').catch(() => {
  return 'return2'
}).catch(err => {
  console.log('catch:', err)
}).then(res => {
  console.log('then:', res)
});   // 'then: return2'
// 'finally'的'return'只会返回与原promise相同的对象
Promise.resolve('resolve').finally(() => {
  return 'return3'
}).then(res => {
  console.log(res)
});   // 'resolve'
// 'reject'状态未被处理的'return'
Promise.reject('reject').then(() => {
  return 'return4'
}).then(res => {
  console.log(res);
});   // 报错!!复制代码

.resolve() 的参数

resolve()(包括Promise.reject()Promise.prototype.reject())除了上面介绍的用法,还能传入thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定。

注意,thenablethen()方法只有传入唯一一个回调函数才会被执行,其他参数会被忽略。

看如下例子:

let thenable = {
  then(cb1, cb2) {
    cb1('cb1');
    cb2('cb2');
  }
}
// Promise.resolve()
Promise.resolve(thenable).then(
  res1 => {
    console.log(res1);  // 'cb1'
  },
  res2 => {
    console.log(res2);  // 不会执行
  }
).catch(err => {
  console.log(err);     // 不会执行
});
// Promise.prototype.resolve()
new Promise((resolve, reject) => {
  resolve(thenable);
}).then(res => {
  console.log(res);     // 'cb1'
});复制代码



分类:
前端
标签:
分类:
前端
标签: