javascript - Promise 如何在 Node.js 和 AWS lambda 函数中工作
问题描述
一般来说,我对 Javascript 和 Node.js 很陌生。因此,我试图了解 Node.js 中异步编程的概念,以及如何在 AWS lambda 中使用它。
我在 Amazon 博客上看到了这篇博文,它解释了 Node.js lambda 函数中对 async/await 的支持:https ://aws.amazon.com/blogs/compute/node-js-8-10-runtime-now-在 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().promise()
如果我只写return await lambda.getAccountSettings()
它会有什么不同。
我可以参考这方面的任何文件吗?
请求您对这种获取承诺对象的新方法进行更多说明。
感谢您提前提供任何帮助。
解决方案
如果您想了解为什么该.promise()
方法可用,以及为什么没有像那样返回承诺,请注意这样的 API 如何随着时间的推移而发展,并且必须保持向后兼容性。
让我们构建一些类似的东西,但要简单得多。让我们创建一个函数,为给定数字提供 1/x,但当 x=0 时提供错误对象。这将异步完成。
此外,我们希望该函数同步返回一个对象,该对象允许在发生错误时注册一个侦听器,在成功时注册一个侦听器,在两者中的任何一个发生时再注册一个。这是 AWS 返回的一个非常简化的想法:在那里你得到了一个非常丰富的Request
对象。
所以想象一下,我们在 2012 年,Promise 还没有在 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);
});
但随后 Promise 变得越来越流行,并且您的 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);
});
如您所见,省略请求对象并让函数返回承诺并不是一个好主意。这会破坏使用您的 API 的现有代码(没有向后兼容性)。
推荐阅读
- python - 将对象集群替换为生成最高 SI 分数的新集群
- c# - 在 Unity 中使用 Firebase 云消息传递时如何获取当前活动?
- javascript - 比较同一对象中的 2 个数组键和值
- c++ - 有没有办法将无向图转换为 (x,y) 坐标系?
- amazon-web-services - AWS Amplify - Cognito,如何知道我的用户有权执行某些操作?
- python - 使用 Python 从新闻网站上抓取评论。将评论隐藏在“显示更多”下的问题
- r - 你能用只有一个水平的自变量在 r 中进行线性回归吗?
- laravel - 多个文件输入类型覆盖选定的文件并仅上传最后一个选定的文件
- kotlin - Kotlin:运算符“!=”不能应用于“字符串?” 和'Char.Companion'
- arrays - 将文件逐行读入C中的字符串数组