【问题标题】:Why do JavaScript try/finally blocks cause function to apparently return twice?为什么 JavaScript try/finally 阻塞会导致函数明显返回两次?
【发布时间】:2019-05-09 18:47:36
【问题描述】:

finally 块总是最后执行,return 语句将控制权返回到函数调用的来源。当在 try/finally 块内部一起使用时,该函数似乎返回两次而不是一次,当在 if-else 块内使用时,finally 块的返回值生效。同一个方法调用会返回两次吗?

function print(value) {
    console.log(value);
    return value;
}

function testWrapped() {
    try {
        return print(true);
    } finally {
        return print(false);
    }
}

function test() {
    try {
        return true;
    } finally {
        return false;
    }
}


console.log("Result with wrapped value");
testWrapped();


console.log("Result when used inside an if statement:");
if (test()) {
    console.log("true");
} else {
    console.log("false");
}

以上代码产生以下输出:

Result with wrapped value
true
false
Result when used inside an if statement:
false

【问题讨论】:

  • 这是我对这种行为的解释,该函数计算返回值的表达式,但在返回之前,它执行 finally 块,这是预期的行为,因为没有什么可以覆盖 finally 的效果块,最后一条语句将控制权返回给调用主体。我在正确的轨道上吗?你有什么想法?

标签: javascript node.js function return-value


【解决方案1】:

这是因为您使用的是finally 而不是catch

最终将在 try 或 catch 之后执行。

在条件块中,它将返回最后评估的项目false,并执行您的 else 块。

见:https://www.w3schools.com/jsref/jsref_try_catch.asp

try 语句允许您定义要测试的代码块 执行时出错。

catch 语句允许您将代码块定义为 执行,如果在 try 块中发生错误。

finally 语句让您在 try 和 catch 之后执行代码, 不管结果如何。

【讨论】:

    【解决方案2】:

    两者都评估,但实际上只有第二个返回。

    由于print()的评价有输出到控制台的副作用,所以可以看到评价。但是如果你是console.log(testWrapped()),你会在两个评估值之后看到返回值。

    您的代码相当于:

    try {
        result1 = print(true);
        return result1;
    }
    finally {
        result2 = print(false);
        return result2;
    }
    

    希望这能让我们更清楚发生了什么。

    【讨论】:

    • 我也是这么想的,'print' 函数让它看起来像是返回了两次,但实际上只计算了返回表达式,返回的实际值是 finally 中的第二个块(问题下方评论中的更多上下文)。感谢您清理它。
    【解决方案3】:

    深入了解它,spec 说:

    TryStatement : try 最终阻止

    1. 令 B 为评估 Block 的结果。
    2. 让 F 成为评估 Finally 的结果。
    3. 如果F.[[type]]正常,则令F为B。
    4. 如果 F.[[type]] 是 return,或者 F.[[type]] 是 throw,则返回 Completion(F )。
    5. 如果 F.[[value]] 不为空,则返回 Completion(F)。
    6. 返回完成{[[type]]: F.[[type]], [[value]]: undefined, [[target]]: F. [[目标]]}。

    将此应用于您的 testWrapped() 代码,

    1. 评估try 块。 print(true) 的副作用发生了,所以true 将出现在控制台中。 try 块返回,因此评估它的结果是 Completion 类型 return 和值 whatever print(true) is: true。 这还没有被退回。
    2. 评估finally 块。同样的事情:false 在控制台中,Completion{[[type]]: return, [[value]]: false}。
    3. “如果 F.[[type]] 是正常的” 不是。接下来。
    4. 这是返回实际发生的地方,它是来自finally 块的返回:false。最终结果:true false 在控制台中,testWrapped() 返回 false。

    还有if 声明:

    1. 评估test 的try 块:Completion{[[type]]: return, [[value]]: true}。
    2. 评估test 的finally 块:Completion{[[type]]: return, [[value]]: false}。
    3. 纳达。
    4. finally 的完成返回:false。 test() 计算结果为 false,然后执行 else 块。

    【讨论】:

      猜你喜欢
      • 2014-08-29
      • 2011-04-19
      • 1970-01-01
      • 2011-12-01
      • 1970-01-01
      • 2021-03-22
      • 1970-01-01
      相关资源
      最近更新 更多