問題

我是Javascript和Node.js的新手.因此,我試圖圍繞Node.js中非同步程式設計的概念以及如何在AWS lambda中使用相同的概念.

我在Amazon部落格上遇到了這篇部落格文章,它解釋了對Node.js lambda函式中非同步/等待的支援: https://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-available-in-aws-lambda/

據我所知,生成承諾的函式的概念如下所示:

 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()它會返回承諾.我假設這方面可能有一個經驗法則.

另外,如果我只寫return await lambda.getAccountSettings()會有什麼區別,而不是return await lambda.getAccountSettings().promise().

有沒有任何文件可以引用?

請您在這個新的方法上更加輕鬆地獲取承諾物件。

感謝提前的任何幫助.

  最佳答案

如果您想了解為什麼提供了 .promise() 方法,以及為什麼承諾不僅僅返回 just-clience-,請注意這樣的 API 是如何隨著時間的推移發展的,並且必須保持向後相容性。

讓我們構建類似的東西,但非常簡化.讓我們建立一個函式,為給定數字提供1 / x,但是當x = 0時出錯物件.這將非同步完成.

此外,我們希望函式同步返回一個物件,允許一個人在發生錯誤時註冊監聽器,另一個在成功時註冊監聽器,另一個在兩者中任何一個發生時返回.這是AWS返回的一個非常簡化的想法:你得到一個非常豐富的 Request 物件.

所以想象一下我們在2012年,承諾尚未在JavaScript中廣泛使用/使用.所以我們為我們的非同步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);
}); 

但隨後承諾變得更受歡迎,您的API的使用者正在推動承諾API.您希望確保向後相容性,因此只是決定將返回的request-object擴充套件到另外一個屬性,一個方法: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);
}); 

如您所見,省略請求物件並使函式返回承諾將不是一個好主意.這將使用您的API破壞現有程式碼(沒有向後相容性).