首页 > 解决方案 > 用这个简单的例子理解 Promise 链

问题描述

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

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

  @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';
  });

标签: javascripttypescriptpromise

解决方案


最后的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处理程序可能是上面第一个代码块中的简洁箭头,但它开始变得丑陋。)


推荐阅读