为什么 AWS Lambda 函数在执行回调函数之前完成?

Why Does AWS Lambda function finishes before callback function is executed?

我正在做一个项目,从音频文件中提取抄本。音频文件的格式为 flac。我正在使用 AWS Lambda 并在节点中编写了代码。此外,我正在使用 IBM Speech to text 服务并使用他们提供的基本示例代码,这些代码可以在 here 中找到。问题是我的 lambda 函数在 运行 这些函数之前完成。

我正在从 s3 下载文件并将其存储在本地(工作正常)。之后,我试图将相同的文件传递给 IBM Speech to Text SDK,它应该 return 将音频文件的转录本

代码如下:

const downloadFile = function (url1, dest, cb) {
    const file = fs.createWriteStream(dest);
    https.get(url1, function (res) {
        //res.setEncoding('binary');
        res.pipe(file);
        file.on('finish', function () {
            const stats = fs.statSync(dest);
            const fileSizeInBytes = stats.size;
        //Convert the file size to megabytes (optional)
            const fileSizeInMegabytes = fileSizeInBytes / 1000000.0;
            console.log(fileSizeInMegabytes);
            file.close();
            RunIBMWatson(dest);
            callback(null,"Nice");
        });
    });
};
function RunIBMWatson(dest){
    console.log(dest);
    console.log("I am here");

    const recognizeStream = speech_to_text.createRecognizeStream(params);
    fs.createReadStream(dest).pipe(recognizeStream);
    recognizeStream.pipe(fs.createWriteStream('/tmp/transcription.txt'));
    recognizeStream.setEncoding('utf8');
    recognizeStream.on('results', function(event) { onEvent('Results:', event); });
    recognizeStream.on('data', function(event) { onEvent('Data:', event); });
    recognizeStream.on('error', function(event) { onEvent('Error:', event); });
    recognizeStream.on('close', function(event) { onEvent('Close:', event); });
    recognizeStream.on('speaker_labels', function(event) { onEvent('Speaker_Labels:', event); });

    function onEvent(name, event) {
      console.log("I am in onEvent");
      if (name === 'data'){
        console.log(event);
      }

这是我从 AWS Lambda 获得的函数日志:

2018-03-05 03:31:53.585 54.093469
2018-03-05 03:31:53.588 /tmp/sample.flac
2018-03-05 03:31:53.588 I am here

我是 AWS Lambda 和 Node.js 的初学者。所以如果有人能指出我犯的错误。

问题是 javascript 事件循环是空的,因此 Lambda 认为它已经完成。您可以下载一个 npm 模块 async/await,这将对此有所帮助。 info here

默认情况下不包含asyncawait,但这并不意味着您不能自己添加它。只需在本地添加包 (npm install asyncawait),并在上传您的 Lambda 函数之前将 node_modules 文件夹包含在您的 ZIP 中。

如果您想单独处理开发依赖项(例如:测试、aws-sdk 在本地执行您的函数等),您可以在 package.json.[=12= 中的 devDependencies 下添加它们]

是的 RunIBMWatson 是一个异步函数,因为文件 IO,所以因为你没有等待该函数的结果到 return - 执行回调从而结束执行你的 lambda。

RunIBMWatson 的逻辑包装在 Promise 中,一旦获取所有数据并将其写入该脚本文件 - 解析函数。 MDN: Promises

const downloadFile = function (url1, dest, cb) {

  ...
  console.log(fileSizeInMegabytes);
  file.close();
  return RunIBMWatson(dest)
  .then(() => { // return data from promise resolve can be back and accessible as params
    callback(null,"Nice");
  }
}

function RunIBMWatson(dest){

  return new Promise((resolve, reject) => {

    const rStream = speech_to_text.createRecognizeStream(params);
    fs.createReadStream(dest).pipe(rStream);

    rStream.pipe(fs.createWriteStream('/tmp/transcription.txt'));
    rStream.setEncoding('utf8');
    rStream.on('results', function(event) { onEvent('Results:', event); });
    rStream.on('data', function(event) { onEvent('Data:', event); });
    rStream.on('error', function(event) { onEvent('Error:', event); });
    rStream.on('close', function(event) { onEvent('Close:', event); });
    rStream.on('speaker_labels', function(event) { onEvent('Speaker_Labels:', event); });

    function onEvent(name, event) {
      console.log("I am in onEvent");
      if (name === 'data'){ // the data 
        resolve(); // you can return data too here
      }
    }
  })
}

希望对您有所帮助