实现 Promise.prototype.finally
手写实现 Promise 的 finally 方法,无论 Promise 成功或失败都会执行回调
问题
Promise.prototype.finally 是 ES2018 引入的方法,用于在 Promise 结束时(无论成功或失败)执行指定的回调函数。需要实现一个符合规范的 finally 方法,要求:
- 无论 Promise 是 fulfilled 还是 rejected,finally 回调都会执行
- finally 回调不接收任何参数
- finally 返回一个新的 Promise,会传递原 Promise 的结果
- 如果 finally 回调返回一个 rejected Promise,则以该 rejected Promise 的原因作为新 Promise 的拒绝原因
解答
Promise.prototype.finally = function(callback) {
return this.then(
// 成功时的处理
value => {
// 执行 callback,并等待其完成(如果返回 Promise)
return Promise.resolve(callback()).then(() => value);
},
// 失败时的处理
reason => {
// 执行 callback,并等待其完成(如果返回 Promise)
return Promise.resolve(callback()).then(() => {
throw reason;
});
}
);
};
更简洁的实现方式:
Promise.prototype.finally = function(callback) {
const P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason; })
);
};
使用示例
// 示例 1:基本使用
Promise.resolve('成功')
.finally(() => {
console.log('清理工作');
})
.then(value => {
console.log(value); // 输出: 成功
});
// 示例 2:失败情况
Promise.reject('失败')
.finally(() => {
console.log('无论成功失败都执行');
})
.catch(error => {
console.log(error); // 输出: 失败
});
// 示例 3:finally 返回 Promise
Promise.resolve('原始值')
.finally(() => {
return new Promise(resolve => {
setTimeout(() => {
console.log('异步清理完成');
resolve();
}, 1000);
});
})
.then(value => {
console.log(value); // 1秒后输出: 原始值
});
// 示例 4:finally 中抛出错误
Promise.resolve('成功')
.finally(() => {
throw new Error('finally 中的错误');
})
.catch(error => {
console.log(error.message); // 输出: finally 中的错误
});
// 示例 5:实际应用场景 - 加载状态管理
function fetchData() {
let loading = true;
console.log('开始加载...');
return fetch('https://api.example.com/data')
.then(response => response.json())
.finally(() => {
loading = false;
console.log('加载完成,关闭 loading');
});
}
关键点
-
使用 then 方法实现:finally 本质上是对 then 方法的封装,同时处理成功和失败两种情况
-
不接收参数:finally 的回调函数不接收任何参数,因为它不关心 Promise 的结果
-
透传原始值:无论成功还是失败,都需要将原始的 value 或 reason 传递给下一个 then/catch
-
Promise.resolve 包装:使用
Promise.resolve(callback())确保即使 callback 返回非 Promise 值也能正确处理 -
保持原始状态:成功时返回原始 value,失败时重新抛出原始 reason
-
支持异步回调:如果 callback 返回 Promise,会等待该 Promise 完成后再传递原始结果
-
错误优先级:如果 finally 回调中抛出错误或返回 rejected Promise,该错误会覆盖原始结果
-
构造函数引用:使用
this.constructor而不是直接使用 Promise,以支持 Promise 的子类
目录