Javascript 最终,未从承诺中确定未定义的解析值背后的原因是什么? 出身背景
TC39现在是该方法的一部分,它还列出了该方法的确切功能Javascript 最终,未从承诺中确定未定义的解析值背后的原因是什么? 出身背景,javascript,promise,language-lawyer,specifications,finally,Javascript,Promise,Language Lawyer,Specifications,Finally,TC39现在是该方法的一部分,它还列出了该方法的确切功能 promise.finally(func)类似于promise.then(func,func),但在几个关键方面有所不同: 在内联创建函数时,您可以传递它一次,而不是被迫声明它两次,或者为它创建变量 finally回调将不会收到任何参数,因为没有可靠的方法来确定承诺是否得到履行或拒绝。这个用例正好适用于您不关心拒绝原因或履行价值的情况,因此不需要提供它 不同于Promise.resolve(2)。然后(()=>{},()=>{})(将使
promise.finally(func)
类似于promise.then(func,func)
,但在几个关键方面有所不同:
- 在内联创建函数时,您可以传递它一次,而不是被迫声明它两次,或者为它创建变量
回调将不会收到任何参数,因为没有可靠的方法来确定承诺是否得到履行或拒绝。这个用例正好适用于您不关心拒绝原因或履行价值的情况,因此不需要提供它finally
- 不同于
(将使用Promise.resolve(2)。然后(()=>{},()=>{})
未定义的
进行解析),
将使用Promise.resolve(2)。最后(()=>{})
进行解析2
- 类似地,不同于
(这将用Promise.reject(3)。然后(()=>{},()=>{})
未定义的
解决),
将用Promise.reject(3)。最后(()=>{})
拒绝(()=>{})3
最后
回调中的抛出
(或返回被拒绝的承诺)将以该拒绝原因拒绝新承诺
换句话说,使用符合的实现的简明多边形填充如下(基于和的答案)
Promise.prototype.finally={
最后(fn){
const oncompleted=()=>这个;
const onfinly=()=>Promise.resolve(fn()).then(oncompleted);
返回这个。然后(肯定地,肯定地);
}
}.最后;
如果我们使用promise#then
和promise#finally
将承诺链与包含try…finally
块的异步函数
进行对比,我们可以确定一些关键差异,这些差异也提到了,但没有详细说明
const completions={
return(label){return`returnfrom${label}`;},
throw(label){throw`throw from${label}`;}
};
功能承诺(tryBlock,finalyblock){
返回承诺。解决()
。然后(()=>完成[tryBlock]('try'))
.finally(()=>完成[finallyBlock]('finallyBlock');
}
异步函数异步(tryBlock,finallyBlock){
try{returncompletions[tryBlock]('try');}
finally{return completions[finallyBlock]('finally');}
}
异步函数测试(tryBlock,finallyBlock){
const onsetled=fn=>result=>console.log(`${fn}()用`${result}`结算);
const promisesetted=onSettled(“承诺”);
const asyncSetted=onSetted('async');
log(`testing try${tryBlock}finallyBlock}`);
等待承诺(tryBlock,finalyblock)。然后(promisesolled,promisesolled);
等待异步(tryBlock,finallyBlock)。然后(asyncsolled,asyncsolled);
}
[['return','return'],['return','throw'],['throw','return'],['throw','throw']]
.reduce((p,args)=>p.then(()=>test(…args)),Promise.resolve()代码>
。作为控制台包装{最大高度:100%!重要}
这表明结果允诺的固定状态的语义不同于模拟try…finally
块
不完全是这样,您只是在比较中使用了“错误的”尝试
/最后
语法。再运行一次
async function async (tryBlock, finallyBlock) {
try { return completions[tryBlock]('try'); }
finally { completions[finallyBlock]('finally'); }
// ^^^^^^ no `return` here
}
您将看到它相当于.finally()
没有实现Promise#finally
的原因是什么,使用Promise解析过程解析为未定义的回调的特殊情况是解析的finally()
重新采用原始承诺状态的唯一条件
该提案给出了:“承诺#最终
将无法修改返回值[…]——因为无法区分“正常完成”和早期返回未定义
,因此与语法最终的并行必须有轻微的一致性差距。”
举一个明确的例子,使用try
/catch
语法,两种语言之间存在语义差异
finally {
}
及
但promise方法无法实现来区分
.finally(() => {
})
及
不,在未定义的
周围引入任何特殊的大小写是没有意义的。总有语义上的差异,用不同的值来实现也不是常见的用例。在正常的<代码>中,你几乎看不到任何代码<返回> /COD>语句。最后,块,大多数人甚至会认为它们是代码气味。只是不适用于堆栈溢出(因为这是一个只有一小部分非常具体的人才能回答的问题)。另一个堆栈交换站点可能更合适,例如,顺便说一句,使用async
作为函数名非常容易混淆,并且在严格模式下无效。@rossipedia有趣的是,Bergi正是我希望得到答案的人,因此,我猜它的结果是:)@Bergi使用async
作为函数名在严格模式下并不是无效的,否则严格模式将无法向后兼容ES2016及更早版本,在这种情况下,通常使用async
作为标识符(例如caolan/async
)。不过,我承认这是令人困惑的。我想你已经指出,我应该删除模拟try…finally
块中的return
语句,我有点同意修改finally
块中函数的返回值是代码味道。另一方面,令我恼火的是,规范本质上阻止了一整类可能的延续,而我建议的语义上的细微变化只阻止了单个值未定义的延续
.finally(() => {
})
.finally(() => {
return undefined;
})