JavaScript 中的调用堆栈中的变量如何在函数 returns 之后仍然可以访问

How are variables in a call stack in JavaScript still accessible after the function returns

两点困惑:

  1. 函数框架是如何保存和处理的?

示例:

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

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

  1. 多个async/promise“returns”

示例:

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 returns。该承诺可能会被解决两次。

Question(s): 超时调用拒绝后,该函数是否仍会 (a) 等待对 return 的数据库调用,然后执行 await 之后的任何代码?第二次履行承诺会发生什么(即 await 完成时的 resolve 调用)是否只处理第一个 resolve/reject?

Coming from the Java world, I am confused as to how this can happen?

这叫做闭包。

函数引用的所有变量都保留在该函数的范围内,无论它在何处或何时执行。这是 JavaScript.

中的基本原则之一

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

  • 将函数声明为 async 的唯一原因是如果您想在内部使用 await
  • 如果内部函数 return 是一个承诺,return 那个承诺。不要创建新的(参见 the Promise construction antipattern)。

所以它应该简单地写成:

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

After the timeout call rejects, will the function still keep (a)waiting for db call to return

是的,这两件事都是独立执行的。除非你建立相互取消机制,否则 setTimeout()dbcall.execute() 都会 运行 完成。

what happens with a second fulfillment of the promise (ie the resolve call when await has completed) Does only the first resolve/reject get processed?

无论有多少内部函数在事后调用 rejectresolve,已解决(解决或拒绝)的承诺将不再更改其最终值。