[JS] Promise.prototype.finally

一、背景

Promise.prototype.finally是目前Stage 4的proposal,将纳入到ES 2018或ES 2019规范中。

[JS] Promise.prototype.finally_第1张图片

promise被settled时有另种情况,或者fulfilled,或者rejected。
如果想要在上述不论哪种被settled的情况下,都做一件事,就不得不写成,

promise.then(f, f);

注意,Promise.prototype.then是可以接受两个函数作为参数的,
第一个函数,会在promise被fulfilled的时候执行,
第二个函数,如果提供了的话,会在promise被rejected的时候执行。

由于promise只能由fulfilled和rejected这两种状态被settled,
所以,这里两个函数,有且只有一个会被执行。

因此,本提案给Promise.prototype添加了一个finally方法,
以更好的表达上述场景的需要。

promise.finally(f);

二、promise.then

不幸的是,
promise.finally(f);的执行结果,是与promise.then(f, f);是不同的。

为了了解有哪些异同,这里有必要回顾一下promise.then(f, f);的返回结果。
下文中“resolved”与“fulfilled”的异同,可以参考:Promise相关的几个术语。

可以简单的认为,fulfilled是promise的结果状态,
而resolved指的是new Promise((res, rej)=> ...);中的res函数被调用。
res只能被调用一次,且它的参数可以是一个promise。

因此,一个resolved的promise,可能处于pending状态,也可能处于settled状态,
最终的settled结果,可能是fulfilled也可能是rejected。

// 1. 这是一个resolved为settled状态的promise
p=new Promise((res,rej)=>{
  res(1);
  res(2);  // 第二次res调用,没有作用
});
// Promise {: 1}

// 2. 这是一个resolved为pending状态的promise,最终fulfilled
p=new Promise((res,rej)=>res(new Promise((res,rej)=>setTimeout(res,1000))));
// Promise {}

p
// Promise {: undefined}

// 3. 这是一个resolved为pending状态的promise,最终rejected
p=new Promise((res,rej)=>res(new Promise((res,rej)=>setTimeout(rej,1000))));
// Promise {}

p
// Promise {: undefined}

以下对promise.then(f, f);的返回结果,分情况进行分析:

(1)如果上述promise被fulfilled了,则第一个f被调用,
否则如果上述promise被rejected了,则第二个f被调用。

这两个f,只会被调用一个,
因此,以下的例子,都用接受单个参数的then(f)来说明问题。

(2)如果被调用的那个f,返回了一个非promise的值,则then会返回一个resolved为该值的promise。如果被调用的那个f,抛了一个异常,则then会返回了一个rejected为该异常的promise。

// 1. 返回一个非promise值

Promise.resolve(1).then(()=>2);
// Promise {: 2}

// 2. 抛异常
Promise.resolve(1).then(()=>{ throw 2; });
// Promise {: 2}

(3)如果被调用的那个f,返回了一个resolved的promise,则then会返回了一个新的具有相同resolved值的promise。如果被调用的那个f,返回了一个rejected的promise,则then会返回了一个新的,具有相同rejected值的promise。

// 1. 返回一个resolved的promise

// 该resolved的proimse,最终fulfilled
Promise.resolve(1).then(()=>new Promise((res,rej)=>res(2)));
// Promise {: 2}

// 该resolved的promise,最终rejected
Promise.resolve(1).then(()=>new Promise((res,rej)=>res(Promise.reject(2))));
// Promise {: 2}

// 2. 返回一个rejected的promise

Promise.resolve(1).then(()=>new Promise((res,rej)=>rej(3)));
// Promise {: 3}

(4)如果被调用的那个f,返回了一个pending的promise,
then也返回一个新的promise。
该promise的settled状态,取决于返回的那个pending promise的settled状态。

// 1. 返回一个pending的最终fulfilled的promise

p=Promise.resolve(1).then(()=>new Promise((res,rej)=>setTimeout(res,1000)));
// Promise {}

p
// Promise {: undefined}

// 2. 返回一个pending的最终rejected的promise

p=Promise.resolve(1).then(()=>new Promise((res,rej)=>setTimeout(rej,1000)));
// Promise {}

p
// Promise {: undefined}

三、promise.finally

下面我们来看一下promise.finally(f);
(1)f是一个无参函数,不论该promise最终是fulfilled还是rejected。
(2)finally不改变promise的状态,

// 1. fulfilled情形

// then返回了一个resolved为2的promise
Promise.resolve(1).then(()=>2,()=>3);
// Promise {: 2}

// finally不改变原来resolved的状态
Promise.resolve(1).finally(()=>2);
// Promise {: 1}

// 2. rejected情形

// then返回了一个resolved为3的promise
Promise.reject(1).then(()=>2,()=>3);
// Promise {: 3}

// finally不改变原来reject的状态
Promise.reject(1).finally(()=>2);
// Promise {: 1}

四、等价的async function写法

// 1. fulfilled情形

Promise.resolve(1).finally(alert);
// Promise {: 1}

f = async ()=>{
  try{
    return 1;
  }finally{
    alert();
  }
};

f();
// Promise {: 1}

// 2. rejected情形

Promise.reject(1).finally(alert);
// Promise {: 1}

f = async ()=>{
  try{
    throw 1;
  }finally{
    alert();
  }
};

f();
// Promise {: 1}

参考

tc39 / proposal-promise-finally
:Promise相关的几个术语

你可能感兴趣的:([JS] Promise.prototype.finally)