【问题标题】:Promise: Then before Resolve承诺:然后在解决之前
【发布时间】:2019-04-13 11:53:30
【问题描述】:

我在 Node.js 中做过的第一件事是,我正在编写一个 AWS Lambda 函数,并且我想在执行其他任何操作之前检查用户的自定义属性是否具有值。因为我被告知 Promises 是同步处理异步方法的方式,所以我编写了函数:

var AWS = require('aws-sdk');
var s3 = new AWS.S3();
var cogId = new AWS.CognitoIdentityServiceProvider();

exports.handler = function (event, context) {

    if (event != null)
    {
        var identityId = context.identity.cognitoIdentityId;

        if (event.userId != null)
        {
            var userId = event.userId;
            PromiseConfirmIdNotSet(userId)
                .then(SetId(userId, identityId))
                .catch();
        }
    }

    context.done(null, 'Hello World');  // SUCCESS with message
};

function PromiseConfirmIdNotSet(userId)
{
    console.log('Entering function');
    return new Promise(function (resolve, reject) {
        console.log('Entering Promise');
        cogId.adminGetUser({
                UserPoolId: myUserPool,
                UserId: userId
            },
            function (err, data) {
                console.log('err = ' + JSON.stringify(err));
                console.log('data = ' + JSON.stringify(err));
                if (data != null && data.UserAttributes.Name == null) {
                    console.log('Calling resolve');
                    resolve();
                } else {
                    console.log('Calling reject');
                    reject();
                }
            });
    });
    console.log('Exiting Promise');
}

function SetId(userId, identityId)
{
    cogId.updateUserAttributes();
}

但是当我运行它时,控制台日志显示“输入函数”,然后显示“输入承诺”,然后执行转到SetId,而没有调用adminGetUser中指定的回调。

如果我在主流程完成后让调试器继续运行,最终我会从回调函数中获取日志,所以它最终会运行。

为什么 Promise 跳到 then 却没有 resolve 被调用?

【问题讨论】:

  • 您能否将您获得的日志输出与您期望的日志输出包括在内?此外,新的 ECMA 规范为您可能想要研究的异步函数(在 AWS Lambda for Node.js 8.10 中支持)提供了新语法,因为它使代码更简洁:async/await:@987654321 @

标签: javascript node.js promise aws-lambda


【解决方案1】:

.then 接受 函数 作为参数。当你这样做时

PromiseConfirmIdNotSet(userId)
  .then(SetId(userId, identityId))
  .catch();

PromiseConfirmIdNotSet 被调用,同步SetId 被调用,而解释器尝试从传递给.then 的函数构造Promise 链。 (但SetId 不返回函数)然后,PromiseConfirmIdNotSet 的异步代码运行,Promise 解析 - 这不是您想要的顺序。

更改它,使SetId 仅在PromiseConfirmIdNotSet 返回的promise 解决之后 被调用:

PromiseConfirmIdNotSet(userId)
  .then(() => SetId(userId, identityId))
  .catch();

问题和原因类似

addEventListener('click', fn());

不起作用 - 您可以将其更改为 , fn);, () => fn());

如果您还希望context.done 仅在成功的SetId 之后出现,则将context.done 调用放在.then 中:

PromiseConfirmIdNotSet(userId)
  .then(() => {
    SetId(userId, identityId);
    context.done(null, 'Hello World');  // SUCCESS with message
  });

【讨论】:

  • 谢谢!这似乎很有效,尽管我预计主线程会在then() 处停止。相反,它按预期运行了PromiseConfirmIdNotSet 函数,然后继续运行到主函数的末尾;回调最终在主要执行完成后的某个时间触发(并显示显然我没有给 adminGetUser 正确的数据,但这是另一回事)。我还需要做些什么来让主线程等待 Promise 链完成执行吗?
  • 你是说context.done(null, 'Hello World');之前应该是吗?如果是这样,那是因为它根本不是 Promise 链 的一部分,所以自然不会等待
  • @Trevortni 查看编辑,但是当前线程永远不会在这样的块内暂停,除非它在 ​​async 函数中遇到 await
  • 正确。就像我说的,这是我第一次使用 Node.js,所以我真的不确定我应该期待发生什么,但我的印象是程序会等待链完成。如果不是这种情况,那么....我想没关系,只要在主线程结束时是否仍有线程在运行并不重要。我认为我实际上不需要为这个函数返回任何东西给调用者,但我很好奇如果需要我应该怎么做;链中的最后一块是否可以返回一个值?
  • @Trevortni Javascript 是单线程的——解释器在任何给定时间都只会移动一段特定的代码。如果产生了另一个线程,比如setTimeout,它只会在当前线程完成后开始运行。
【解决方案2】:

您可以简单地将 async-await 用于简洁的异步函数。这是您的异步​​等待代码。如果您发现更多问题,请检查并告诉我。

exports.handler = async function (event, context) {
 if (event != null)
 {
   var identityId = context.identity.cognitoIdentityId;

   if (event.userId != null)
   {
     var userId = event.userId;
     await PromiseConfirmIdNotSet(userId);
     await SetId(userId, identityId);
   }
 }

 await context.done(null, 'Hello World');  // SUCCESS with message
};

function PromiseConfirmIdNotSet(userId)
{
  console.log('Entering function');
  return new Promise(function (resolve, reject) {
  console.log('Entering Promise');
  cogId.adminGetUser({
    UserPoolId: myUserPool,
    UserId: userId
  },
  function (err, data) {
    console.log('err = ' + JSON.stringify(err));
    console.log('data = ' + JSON.stringify(err));
    if (data != null && data.UserAttributes.Name == null) {
        console.log('Calling resolve');
        resolve();
    } else {
      console.log('Calling reject');
      reject();
    }
  });
});
 console.log('Exiting Promise');
}

function SetId(userId, identityId)
{
  cogId.updateUserAttributes();
}

【讨论】:

    猜你喜欢
    • 2015-06-24
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 2021-08-11
    • 2015-06-23
    • 2015-07-18
    相关资源
    最近更新 更多