函数返回后,JavaScript中调用堆栈中的变量如何仍然可以访问

函数返回后,JavaScript中调用堆栈中的变量如何仍然可以访问,javascript,promise,callstack,asynchronous-javascript,Javascript,Promise,Callstack,Asynchronous Javascript,有两点混淆: 如何保存和处置功能框架 例如: function foo() { var a = ...; setTimeout(function() { console.log(a); },50); return a; } async function foo2() { var p = new Promise() { setTimeout(function() { p.reject(null); },60000); p.resol

有两点混淆:

  • 如何保存和处置功能框架
  • 例如:

    function foo() {
      var a = ...;
      setTimeout(function() {
        console.log(a);
      },50);
      return a;
    }
    
    async function foo2() {
      var p = new Promise() {
        setTimeout(function() {
          p.reject(null);
        },60000);
        p.resolve(await dbcall.execute());
      }
      return p;
    }
    
    在本例中,setTimeout中的内部函数引用外部变量a,即使在foo返回之后也是如此。来自Java世界,我很困惑这是如何发生的?如何存储foo堆栈帧以供内部函数使用,以及何时从堆栈中弹出

  • 多个异步/承诺“返回”
  • 例如:

    function foo() {
      var a = ...;
      setTimeout(function() {
        console.log(a);
      },50);
      return a;
    }
    
    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调用返回,然后执行wait之后出现的任何代码?第二次履行承诺(即等待完成时的解析调用)会发生什么情况?只有第一次解析/拒绝得到处理吗

    来自Java世界,我很困惑这是如何发生的

    这叫做结束

    函数引用的所有变量都保留在该函数的作用域中,无论它位于何处或何时执行。这是JavaScript的基本原则之一

    你的第二个例子没有意义

    • 将函数声明为
      async
      的唯一原因是希望在内部使用
      wait
    • 如果内部函数返回承诺,则返回该承诺。不要创建新的(请参见)
    所以应该简单地说:

    function foo2() {
      return dbcall.execute();
    }
    
    或者,用粗箭头语法

    const foo2 = () => dbcall.execute();
    
    为了生成超时,可以使用
    Promise.race()

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

    const foo2 = () => new Promise((resolve, reject) => {
        dbcall.execute().then(resolve).catch(reject);
        setTimeout(() => reject('timeout'), 60000);
    });
    
    在超时调用被拒绝后,函数是否仍保持(a)等待db调用返回

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

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


    无论事实发生后有多少内部函数调用
    reject
    resolve

    “是否只处理了第一个解决/拒绝?”似乎很容易测试出……1。二,。这是一个承诺,这意味着它检查它是否得到解决,承诺本身就是一个目标;第二个知道它已经完成,并且马上决定(或拒绝)。这就像一个任务,如果Java有类似的东西(这里是C#person)
    假设超时调用首先发生,然后dbcall返回。承诺可能会被解决两次
    不真实。。第一次解决/拒绝将履行“功能框架如何保存和处置?”的承诺。问题:每个功能都创建了一个新的范围。正如您所期望的那样,作用域是嵌套的,并从内部向外引用。函数是对象——只要它们是活动的,它们的引用就不会被垃圾收集。这适用于执行延迟的函数。警告:外部作用域值可能在引用它的函数运行之前更改。作用域仅捕获变量引用,您将始终获得当前值。@Tomalak谢谢!