Обещание: тогда, прежде чем разрешить - PullRequest
0 голосов
/ 10 ноября 2018

Самое первое, что я когда-либо делал в Node.js, я пишу лямбда-функцию AWS и хочу проверить, имеет ли пользовательский атрибут пользователя значение, прежде чем делать что-либо еще. Поскольку мне сказали, что 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.

Если я позволю отладчику продолжить работу после завершения основного потока, в конце концов я получу журналы от функции обратного вызова, так что она в конечном итоге запустится.

Почему Обещание пропускается к тому моменту, когда resolve никогда не вызывают?

Ответы [ 2 ]

0 голосов
/ 10 ноября 2018

Вы можете просто использовать 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();
}
0 голосов
/ 10 ноября 2018

.then принимает функцию в качестве аргумента. Когда вы делаете

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

PromiseConfirmIdNotSet вызывается и синхронно , SetId вызывается, в то время как интерпретатор пытается построить цепочку Promise из функции, переданной в .then. (Но SetId не возвращает функцию) Затем, после этого, выполняется асинхронный код PromiseConfirmIdNotSet, и Promise разрешается - что не в том порядке, в котором вы хотите.

Измените его так, чтобы SetId вызывался только после , обещание, возвращенное PromiseConfirmIdNotSet, разрешается:

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
  });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...