javascript - Promise 如何在 Node.js 和 AWS lambda 函数中工作

标签 javascript node.js amazon-web-services promise aws-lambda

总的来说,我对 Javascript 和 Node.js 还很陌生。因此,我试图了解 Node.js 中异步编程的概念以及如何在 AWS lambda 中使用它。

我在亚马逊博客上看到这篇博文,其中解释了 Node.js lambda 函数中对异步/等待的支持:https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/

据我所知,生成 promise 的函数的概念如下面的代码片段所示:

const func1 = () => {
    console.log("Starting with execution of func1...")
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("First promise ended after 3 secs")
        }, 3000)
    })
}

所以这里的函数显式地生成一个 Promise 并返回它。

但在上面的 AWS 博客文章中,我看到了这样一个函数定义:

let AWS = require('aws-sdk');
let lambda = new AWS.Lambda();

exports.handler = async (event) => {
    return await lambda.getAccountSettings().promise() ;
};

现在我已经检查了 AWS SDK for Node.js 文档 (https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#getAccountSettings-property),我看到函数 getAccountSettings 接受回调作为第三个参数。

我对生成 promise 的 .promise() 语法感到困惑。一个函数如何确保使用该语法它会返回一个 promise 对象。因为从文档中没有提到如果我使用 .promise() 它会返回一个 promise 。我假设在这方面可能存在经验法则。

如果我只是写 return await lambda.getAccountSettings().promise() 而不是 return await lambda.getAccountSettings().promise() 会有什么不同呢。

有没有我可以引用的相关文档?

请您进一步说明这种取回 promise 对象的新方法。

提前感谢您的帮助。

最佳答案

如果您想了解为什么可以使用 .promise() 方法,以及为什么不直接返回 promise,请注意这样的 API 是如何随着时间的推移而演变的,并且必须保持向后兼容性。

让我们构建一些类似的东西,但要简化得多。让我们创建一个函数,它为给定数字提供 1/x,但在 x=0 时提供错误对象。这将异步完成。

此外,我们希望该函数同步返回一个对象,该对象允许一个人在发生错误时注册一个监听器,在成功时注册一个监听器,在两者中的任何一个发生时注册一个监听器.这是 AWS 返回的一个非常简化的想法:在那里你得到了一个非常丰富的 Request对象。

假设我们在 2012 年,而 JavaScript 中的 promise 尚未广泛可用/使用。因此,我们为我们的异步 1/x 函数提供以下 API:

// Implementation in the first version of the API (without promises):
//    * returns an object with which you can register a listener
//    * accepts an optional callback
function getAsyncInverse(num, callback) {
    var onSuccess = [], // callbacks that are called on success
        onError = [], // callbacks that are called on failure
        onComplete = [];  // callbacks that are called in both situations
    if (callback) onComplete.push(callback);
    
    function complete(err=null) {
        var result = null;
        if (num === 0) err = new Error("Division by Zero");
        else result = 1/num;
        // Communicate the result/error to the appropriate listeners:
        if (err) for (var i = 0; i < onError.length; i++) onError[i](err);
        else for (var i = 0; i < onSuccess.length; i++) onSuccess[i](result);
        for (var i = 0; i < onComplete.length; i++) onComplete[i](err, result);
    }

    var timeoutId = setTimeout(complete, 100);

    var request = {
        on: function (type, callback) {
            if (type === "success") onSuccess.push(callback);
            else if (type === "error") onError.push(callback);
            else if (type === "complete") onComplete.push(callback);
            return request;
        },
        abort: function () {
            clearTimeout(timeoutId);
            complete(new Error("aborted"));
            return request;
        }
    }
    
    return request;
}

// How version 1 is used, by registering a listener via the returned object
var num = 2;
var request = getAsyncInverse(num); // let's not pass a callback here
request.on("success", function (result) { // ... but use the request object
    console.log("The result is:", result);    
}).on("error", function (err) {
    console.log("There was an error:", err);
});

但随后 promises 变得越来越流行,您的 API 的用户正在插入 promise API。您希望确保向后兼容性,因此决定只使用一个附加属性扩展返回的请求对象,一种方法:promise()

下面是如何改变上述实现以实现这一点:

// Implementation in the second version of the API (with promise), but backwards-compatible
//    * returns an object with which you can register a listener, or get the promise object
//    * accepts an optional callback
function getAsyncInverse(num, callback) {
    let onSuccess = [], // callbacks that are called on success
        onError = [], // callbacks that are called on failure
        onComplete = [];  // callbacks that are called in both situations
    if (callback) onComplete.push(callback);
    
    let request;
    // New: create a promise, and put the logic inside the promise-constructor callback
    let promise = new Promise(function (resolve, reject) {
        function complete(err=null) {
            let result = null;
            if (num === 0) err = new Error("Division by Zero");
            else result = 1/num;
            // Communicate the result/error to the appropriate listeners:
            if (err) for (let callback of onError) callback(err);
            else for (let callback of onSuccess) callback(result);
            for (let callback of onComplete) callback(err, result);
            // New: also call resolve/reject
            if (err) reject(err);
            else resolve(result);
        }

        let timeoutId = setTimeout(complete, 100);
        
        request = {
            on: function (type, callback) {
                if (type === "success") onSuccess.push(callback);
                else if (type === "error") onError.push(callback);
                else if (type === "complete") onComplete.push(callback);
                return request;
            },
            abort: function () {
                clearTimeout(timeoutId);
                complete(new Error("aborted"));
                return request;
            },
            promise: function () { // <--- added feature!
                return promise;
            }
        };
    });

    return request; // We return the same as in version-1, but with additional promise method
}

// How version 2 is used, by getting the new promise method
let num = 2;
let promise = getAsyncInverse(num).promise();
promise.then(function (result) {
    console.log("The result is:", result);    
}).catch(function (err) {
    console.log("There was an error:", err);
});

如您所见,省略请求对象并让函数返回 promise 并不是一个好主意。这会破坏使用您的 API 的现有代码(不向后兼容)。

关于javascript - Promise 如何在 Node.js 和 AWS lambda 函数中工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58154076/

相关文章:

javascript - 我试图在没有数据库的情况下进行密码验证,只有一个密码

javascript - 存储不带括号和引号的 JSON

javascript - 除了可扩展性之外,还有哪些使用 node.js 的架构原因?

amazon-web-services - AWS Lambda@edge。如何从 S3 读取 HTML 文件并将内容放入响应正文中

javascript - 点击类(class)时执行一些操作

javascript - 我的导航中有一个嵌套的 ul,为什么它不显示移动列表中的所有内容?

javascript - socket.io:如何放弃 url:port 方案?

amazon-web-services - 验证 ALB + AWS Cognito 时出现 500 错误

amazon-web-services - Amazon HTTP API 网关无法通过 VPC 链接工作

javascript - Emberjs 应用程序在除 Index 之外的所有路由上加载