Javascript 最终,未从承诺中确定未定义的解析值背后的原因是什么? 出身背景

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)。然后(()=>{},()=>{})(将使

TC39现在是该方法的一部分,它还列出了该方法的确切功能

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;
})