在 finally 块中进行清理,在 try 块中使用 return - 不好的做法?

Doing clean-up inside finally block, with return in try block - bad practice?

我有这段代码可以计算出一些文本的宽度:

function textWidth(text, font) {
    const span = document.createElement('span')
    try {
        span.style.cssText = `position: absolute; opacity: 0; font: ${font || "'Arial'"};`
        span.innerText = text
        document.body.appendChild(span)

        return span.offsetWidth
    } finally {
        document.body.removeChild(span)
    }
}

当 try 块 returning 某些东西时,在 finally 中进行清理是不是不好的做法?它按预期工作;这个问题不是关于 try...finally 如何工作的,我明白了。我只是想知道是否出于某种原因将宽度存储在变量中,进行清理,然后 return 变量会更好吗?

Is it bad practice to do the clean-up inside finally when the try block is returning something?

不,这是完全正常的做法。

当你做return span.offsetWidth时,span.offsetWidth的值被评估并放在一边,然后finally代码是运行,然后那个值是return编辑。无需手动执行此操作。您的 finally 甚至可以包含 span = null;,它不会影响您的 return 值,因为表达式 span.offsetWidth 已经 当时已进行评估。

您可以在 the spec 中看到:

Runtime Semantics: Evaluation

ReturnStatement: return Expression;

  1. Let exprRef be the result of evaluating Expression.
  2. Let exprValue be ? GetValue(exprRef).
  3. If ! GetGeneratorKind() is async, set exprValue to ? Await(exprValue).
  4. Return Completion { [[Type]]: return, [[Value]]: exprValue, [[Target]]: empty }.

在那段摘录中,值在exprValue中,它成为完成记录的一部分(这是一种规范机制,不一定是真实的);然后 finally 代码是 运行,并且该函数完成该完成记录(当然,除非 finally 抛出或发出一个不同的 return 来取代这个 return).

你也可以观察一下:

function example() {
  let foo = () => {
    console.log("foo called");
    return 42;
  };
  try {
    console.log("Doing: return foo();");
    return foo();
  } finally {
    console.log("finally block, doing foo = null");
    foo = null;
  }
}
console.log(example());