如何在 Edge 中添加 polyfill 以支持 finally()?
Posted
技术标签:
【中文标题】如何在 Edge 中添加 polyfill 以支持 finally()?【英文标题】:How to add a polyfill to support finally() in Edge? 【发布时间】:2019-04-19 01:02:14 【问题描述】:我正在使用 axios 库并使用 then()、catch() 和 finally()。在 Chrome 中完美运行。但是 finally() 方法在 MS Edge 中不起作用。我使用 polyfills 或 shims 进行了研究,但我迷路了。我没有使用 webpack 或转译,也不打算添加它们。我需要保持简单。如何添加 polyfill 以确保 finally() 在 Edge 中工作?谢谢!
【问题讨论】:
你可以考虑看看这个库:github.com/es-shims/Promise.prototype.finally 【参考方案1】:除了下面详述的行为之外,这应该处理 thenable 的 species
的传播:
Promise.prototype.finally = Promise.prototype.finally ||
finally (fn)
const onFinally = callback => Promise.resolve(fn()).then(callback);
return this.then(
result => onFinally(() => result),
reason => onFinally(() => Promise.reject(reason))
);
.finally;
此实现基于 finally()
的记录行为,并取决于 then()
是否符合规范:
finally
回调不会收到任何参数,因为没有可靠的方法来确定承诺是否被履行或拒绝。此用例正好适用于您不关心拒绝原因或履行价值的情况,因此无需提供。与
Promise.resolve(2).then(() => , () => )
(将使用undefined
解析)不同,Promise.resolve(2).finally(() => )
将使用2
解析。同样,与
Promise.reject(3).then(() => , () => )
(将使用undefined
实现)不同,Promise.reject(3).finally(() => )
将被3
拒绝。注意:
finally
回调中的throw
(或返回被拒绝的承诺)将拒绝新的承诺,并在调用throw()
时指定拒绝原因。
当然还有等效行为的演示:
const logger = (label, start = Date.now()) => (...values) =>
console.log(label, ...values, `after $Date.now() - startms`);
;
const delay = (value, ms) => new Promise(resolve =>
setTimeout(resolve, ms, value);
);
// run test on native implementation
test('native');
// force Promise to use the polyfill implementation
Promise.prototype.finally = /* Promise.prototype.finally || */
finally (fn)
const onFinally = callback => Promise.resolve(fn()).then(callback);
return this.then(
result => onFinally(() => result),
reason => onFinally(() => Promise.reject(reason))
);
.finally;
// run test on polyfill implementation
test('polyfill');
function test (impl)
const log = ordinal => state => logger(`$ordinal $impl $state`);
const first = log('first');
// test propagation of resolved value
delay(2, 1000)
.finally(first('settled'))
.then(first('fulfilled'), first('rejected'));
const second = log('second');
// test propagation of rejected value
delay(Promise.reject(3), 2000)
.finally(second('settled'))
.then(second('fulfilled'), second('rejected'));
const third = log('third');
// test adoption of resolved promise
delay(4, 3000)
.finally(third('settled'))
.finally(() => delay(6, 500))
.then(third('fulfilled'), third('rejected'));
const fourth = log('fourth');
// test adoption of rejected promise
delay(5, 4000)
.finally(fourth('settled'))
.finally(() => delay(Promise.reject(7), 500))
.then(fourth('fulfilled'), fourth('rejected'));
.as-console-wrappermax-height:100%!important
感谢 @Bergi 对此答案的意见。如果您觉得这篇文章有帮助,请查看his implementation 并点赞。
【讨论】:
内置 finally 函数是否保证在所有then()
和 catch()
之后被调用。如果没有,这可能会有风险
@Evert 不,它没有,.finally()
是按照它在链中的顺序调用的,就像任何其他 promise 方法一样。
谢谢帕特里克,我刚刚测试了你的代码,完美运行!我认为我让 polyfill 过于复杂,现在我意识到它们相当简单。
@PatrickRoberts 我看不出有什么问题。它与更新后的基本相同,只是状态传播方式不同。我较短的方法——返回原始承诺作为结果——有点奇怪,但我相信它有效。队列中的承诺作业数量可能与规范要求的不同,但我忽略了这一点。
顺便说一句,关于物种,我认为通过返回 then
方法创建的内容,我们做的一切都是正确的。唯一的区别是 Promise.resolve
而不是 this.constructor.resolve
但 imo 这无关紧要以上是关于如何在 Edge 中添加 polyfill 以支持 finally()?的主要内容,如果未能解决你的问题,请参考以下文章