使用节点8.10在AWS Lambda中未调用setImmediate()回调

时间:2018-11-08 17:42:27

标签: node.js lambda

我想了解为什么在以下情况下不会调用setImmediate的回调:

module.exports.handler = async (event, context, callback) => {
  try {
    console.log('calling setImmediate...');
    setImmediate(function () {
      console.log('setImmediate callback invoked!');
      callback(null, 'OK!!!!');
    })
  } catch (e) {
    console.log('Failed!');
    console.log(e);
    callback(e);
  }
};

CloudWatch中的输出如下:

START RequestId: c2b83f7b-e37a-11e8-ba70-5b99f76ce7ed Version: $LATEST
2018-11-08T17:21:42.922Z    c2b83f7b-e37a-11e8-ba70-5b99f76ce7ed    calling setImmediate...
END RequestId: c2b83f7b-e37a-11e8-ba70-5b99f76ce7ed
REPORT RequestId: c2b83f7b-e37a-11e8-ba70-5b99f76ce7ed  Duration: 35.99 ms  Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 19 MB

删除'async'关键字即可解决,但我不明白为什么。

我尝试在lambda环境之外重现此行为:

async function test(){
  setImmediate(function(){
    console.log('setImmediate callback!')
  })
}

test()

但是在此示例中,回调被调用。

任何人都可以指出正确的方向来理解这一点吗?

2 个答案:

答案 0 :(得分:1)

如果您返回async函数所做的诺言,则当诺言得到解决时,您的lambda会结束。由于您的异步函数不包含任何await表达式,因此它返回的承诺将立即得到解决。您不能同时进行回调并返回承诺。

对于await上的setImmediate,您必须创建一个承诺,该承诺将在其回调触发时解析。将您的callback(e)转换为被拒绝的承诺,并将您的callback(null, 'OK!!!!')转换为已解决的承诺:

module.exports.handler = async (event, context) => {
  try {
    console.log('calling setImmediate...');
    return await new Promise((resolve, reject) => {
      setImmediate(function () {
        console.log('setImmediate callback invoked!');
        resolve('OK!!!!');
      });
    });
  } catch (e) {
    console.log('Failed!');
    console.log(e);
    throw e;
  }
};

答案 1 :(得分:0)

在节点8中使用异步调用处理程序时,您不应使用回调。

在节点8中声明为异步的函数实际上正在返回诺言。因为您正在声明回调,所以setImmediate函数试图解析第二个Promise,因此您实际上已经设置了一个竞争条件,其中lambda在函数内部运行控制台日志语句之前结束。无论哪种方式,您实际上都不会得到想要的响应。

尝试:

module.exports.handler = async (event, context) => {
  try {
    console.log('calling setImmediate...');
    var setImmediate = (function () {
      console.log('setImmediate callback invoked!');
      return('OK!!!!');
    });
    return setImmediate();
  } catch (e) {
    console.log('Failed!');
    console.log(e);
    return(e);
  }
};

如果删除异步声明,您的代码将起作用,因为仍然支持旧的回调语法。