Promise 中不调用 resolve 与 reject 产生的结果

有如下代码

// test.js

async function fun1() {
    try {
        await fun2();
    } catch (error) {
        console.log('error');
    }
}

function fun2() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            // resolve();
            reject();
        }, 500);
    });
}

fun1();

在控制台执行 node test.js,产生以下情况

  • fun2promise 中,如果我调用 resolve 或者 reject,控制台会等待 500ms
  • 如果我不执行 setTimeout 他会立马结束程序执行

在我的理解中,promise 有三种状态:执行中、成功、失败。既然我没有调用 resolve 或者 reject 他应该是一种 执行中 的状态,那么程序不应该结束才对,应该一直处于等待状态;实际的情况是,立马结束了,请问我的理解哪里出错了?

阅读 9.3k
2 个回答
async function fun1() {
  try {
    await fun2();
  } catch (error) {
    console.log("error");
  }
}

function fun2() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // resolve();
      // reject();
    }, 10000);
  });
}

fun1();

为了让现象更清楚,我加大了 setTimeout 的时长,在这种情况下不执行 resolve/reject 程序会在 10000ms 后结束。

如果 “程序不应该结束才对,应该一直处于等待状态” 指的是10000ms后程序还应该在等待,那么可以这么理解:程序主线程执行fun2函数,函数入调用栈,执行new Promise 主体时遇到 setTimeoutsetTimeout 会交由主线程外的 Web API 处理,fun2函数执行完毕,此时任务队列为空已经没有任务需要执行,但程序还不能退出因为主线程外还有其他工作在进行,等到 10000ms 结束满足 setTimeout 触发机制,回调函数进入宏任务队列,Event Loop 从宏任务队列取出任务执行,执行完毕,主线程和其他部门都没有在进行工作,程序退出。

如果在 setTimeout 里调用了 resolve/reject 只是往微任务队列里加了后续的回调步骤,主动调用那么程序会继续执行,不调用没任务要做了那么程序结束。

这个问题其实不简单,参见 知乎上的这个问题
我看了一些答案,得到的结论是:

  • 从语法的层面,你的想法是符合逻辑的,Promise 应该一直 pending 直到 resolve或者 reject(这种 Promise 有专门的描述 “forever pending promise”,说明 TC39 考虑过这个问题,但最终把此类 Promise 的处理问题留给引擎开发者来解决);
  • 从引擎的层面,可以通过诸多方面来判断在执行的程序是否需要继续执行,如果无需执行,就可以结束,不会考虑 Promise 的状态,就算程序不结束,没被引用的 Promise 所占内存都可能被回收,那它的状态就更不重要了。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题