0

混淆的两点:

  1. 功能框架是如何保存和处置的?

例子:

function foo() {
  var a = ...;
  setTimeout(function() {
    console.log(a);
  },50);
  return a;
}

在这个例子中,setTimeout 中的内部函数正在引用外部变量 a,即使在 foo 返回之后也是如此。来自 Java 世界,我很困惑这怎么会发生?foo 堆栈帧如何存储以供内部函数使用,何时从堆栈中弹出?

  1. 多个异步/承诺“返回”

例子:

async function foo2() {
  var p = new Promise() {
    setTimeout(function() {
      p.reject(null);
    },60000);
    p.resolve(await dbcall.execute());
  }
  return p;
}

在其他地方:

foo2.then(resolve, reject) {
  ...
}

假设先发生超时调用,然后 dbcall 返回。承诺可能会被解决两次。

问题:超时调用拒绝后,该函数是否仍会继续(a)等待 db 调用返回,然后执行等待之后的任何代码?第二次履行承诺会发生什么(即等待完成时的解析调用)是否只有第一次解析/拒绝得到处理?

4

1 回答 1

1

来自 Java 世界,我很困惑这怎么会发生?

这叫做闭包。

函数引用的所有变量都保留在该函数的作用域内,无论它在哪里,或者何时执行。它是 JavaScript 的基本原则之一。

你的第二个例子没有意义。

  • 声明函数的唯一原因async是如果您想在await内部使用。
  • 如果内部函数返回一个 Promise,则返回该 Promise。不要创建一个新的(参见Promise 构造反模式)。

所以它应该简单地阅读:

function foo2() {
  return dbcall.execute();
}

或者,在粗箭头语法中

const foo2 = () => dbcall.execute();

为了生成超时,您可以使用Promise.race().

const timeout = (promise, ms) => Promise.race([
    new Promise((_, reject) => setTimeout(() => reject('timeout'), ms)),
    promise
]);

timeout(foo2(), 60000).then(foo2Result => {
    // success
}).catch(error => {
    // either 'timeout' or an error from dbcall
});

但是如果你想把它包装在一个新的承诺中,你可以——以牺牲可组合性为代价:

const foo2 = () => new Promise((resolve, reject) => {
    dbcall.execute().then(resolve).catch(reject);
    setTimeout(() => reject('timeout'), 60000);
});

超时调用拒绝后,该函数是否仍会继续(a)等待 db 调用返回

是的,这两件事都是独立执行的。除非您建立相互取消机制,否则 thesetTimeout()和 thedbcall.execute()都将运行到完成。

承诺的第二次履行会发生什么(即等待完成时的解决调用)是否只有第一次解决/拒绝得到处理?

reject无论有多少内部函数调用或resolve事后调用,已解决(已解决或已拒绝)的 Promise 将不再改变其最终值。

于 2021-06-01T17:47:49.487 回答