【问题标题】:Understanding promise chaining with this simple example用这个简单的例子理解 Promise 链
【发布时间】:2018-05-08 02:50:41
【问题描述】:

我需要以下逻辑,但我不明白。当找到用户(不是undefined)时,我需要比较返回boolean 的密码(另一个承诺)。需要:

  • 当用户不存在时返回undefined (HTTP 404)
  • 密码错误时抛出ForbiddenError (HTTP 403)
  • 当用户存在且密码匹配时返回user (HTTP 200)

第一次尝试(丑陋,不可读):

  @Post()
  login(
    @BodyParam('username', { required: true }) username: string,
    @BodyParam('password', { required: true }) plainPassword: string,
  ) {

    return this.userRepository.findOne({ username: username, enable: true })
      .then ((user: User | undefined) => {
        if (!user) {
          return undefined; // 404
        }

        return bcrypt.compare(plainPassword, user.password)
          .then(passwordMatch => {
            if (!passwordMatch) {
              throw new ForbiddenError('Authentication failed.'); // 403
            }

            return user; // 200
          });
      });
  }

第二次尝试无效,总是返回'ok'

return this.userRepository.findOne({ username: username, enable: true })
  .then((user: User | undefined) => {
    if (!user) {
      return undefined; // 404
    }

    return bcrypt.compare(password, user.password);
  })
  .then(passwordMatch => {
    // Doesn't work: this is executed every time (even if user is undefined).

    return 'ok';
  });

【问题讨论】:

  • 那么第一个有效吗?真的是那么可怕吗?
  • 由于您正在链接,因此在您的第二个 sn-p 中,您需要 throw 一个错误而不是返回 undefined 来打破承诺链。
  • @ionizer 好的,我明白了。如果我在第二个 then(第二个示例)中抛出,我如何获取用户变量(用于返回它)?
  • @JaredSmith 现在没那么难看,但我将来可能需要添加更多检查。
  • 您始终可以使用.catch() 块来处理您的错误。但是为什么你会在抛出之后使用undefined 用户变量呢?

标签: javascript typescript promise


【解决方案1】:

你最后的 then 处理程序总是运行(好吧,如果承诺不拒绝),因为如果用户不存在,第一个承诺用 undefined 解决,如果用户存在,则用布尔值解决存在。

您的嵌套版本很好。如果你需要在成功的情况下返回user,这可能是要走的路。

但是,如果您只需要在成功案例中返回 'ok',就像在您的第二个代码示例中一样,您可以展平事物,您只需要处理 undefined,如果没有用户。如果找不到用户,我们还可以利用您知道user 将具有值undefined 的事实:

return this.userRepository.findOne({ username: username, enable: true })
  // The `then` below returns `undefined` if `user` is `undefined`, the promise from `compare` otherwise
  .then((user: User | undefined) => user && bcrypt.compare(password, user.password))
  .then(passwordMatch => {
    if (passwordMatch === undefined) {
      // No user
      return undefined;
    } else if (!passwordMatch) {
      // Bad password
      throw new ForbiddenError('Authentication failed.'); // 403
    } else {
      // All good
      return 'ok';
    }
  });

如果您想将其展平返回user,那么您需要将user 传播到下一个处理程序:

return this.userRepository.findOne({ username: username, enable: true })
  .then((user: User | undefined) => {
    return !user
        ? {user} // will be {undefined}
        : bcrypt.compare(password, user.password)
            .then(passwordMatch => ({user, passwordMatch})); // *** Note making an object
  })
  .then(({user, passwordMatch}) => { // *** Note destructuring
    if (user === undefined) {
      // No user
      return undefined;
    } else if (!passwordMatch) {
      // Bad password
      throw new ForbiddenError('Authentication failed.'); // 403
    } else {
      // All good
      return user; // 200
    }
  });

(第一个 then 处理程序可能是一个简洁的箭头,就像上面的第一个代码块一样,但它开始变得丑陋了。)

【讨论】:

  • 我可能喜欢在第一个 then(第一个代码示例)中返回 undefinedcompare 的结果的想法。但我需要返回用户。
  • @ionizer:谢谢! 实际上,情况比这更糟——在这种情况下解构会失败,而我没有处理它。我现在已经解决了,感谢您的帮助。
  • @gremo:如果您需要返回user,那么我要么坚持使用您的嵌套处理程序,要么使用上述答案中的(更正的)最终方法。
【解决方案2】:

当您 return undefined 时,这会使第一个 then() 回调的承诺解析为 undefined

然后执行您的第二个then() 回调,接收undefined 作为参数。

您应该更改第二个回调来检查。

【讨论】:

    猜你喜欢
    • 2021-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-22
    • 2019-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多