一个承诺可以解决两次吗?

Can one promise be resolved twice?

我有这样的功能:

async howLongToMyBirthdayDate(date) {
    return await new Promise((resolve, reject) => {
      let bday;
      if (!(date instanceof Date)) {
        if (Number.isInteger(date) && date > 0) {
          bday = new Date(date);
        } else {
          setTimeout(() => reject(new Error('Wrong argument!')), 1000);
          return;
        }
      } else {
        bday = date;
      }

      const today = new Date();
      today.setHours(0, 0, 0, 0);

      bday.setFullYear(today.getFullYear());
      bday.setHours(0, 0, 0, 0);

      if (bday - today === 0) {
        setTimeout(() => resolve(this.congratulateWithBirthday()), 1000);
        
      }

      setTimeout(
        () =>
          resolve(this.notifyWaitingTime(Math.ceil((bday - today) / 86400000))),
        1000
      );
    });
  }

承诺解决了两次。我看到函数 congratulateWithBirthday 和 notifyWaitingTime 的结果。正常吗?我认为 promise 只能被解决或拒绝一次——通过第一次调用 resolve 或 reject 回调。也许 setTimeout 改变了它的行为?谁能给我解释一下?

您的承诺无需解析两次即可获得您描述的行为。您直接调用了这两个函数,因此它们当然会被调用。第二次调用 resolve 是否执行任何操作无关。

这一行

resolve(this.notifyWaitingTime(Math.ceil((bday - today) / 86400000))),

不是说“解析然后运行这个函数”,而是说“调用这个函数,然后用它的return值调用解析”。

编写此代码的更合适的方式可能是这样的:

async howLongToMyBirthdayDate(date) {
    const result = await new Promise((resolve, reject) => {
      let bday;
      if (!(date instanceof Date)) {
        if (Number.isInteger(date) && date > 0) {
          bday = new Date(date);
        } else {
          setTimeout(() => reject(new Error('Wrong argument!')), 1000);
          return;
        }
      } else {
        bday = date;
      }

      const today = new Date();
      today.setHours(0, 0, 0, 0);

      bday.setFullYear(today.getFullYear());
      bday.setHours(0, 0, 0, 0);

      // resolve with how long until bday
      if (bday - today === 0) {
        setTimeout(() => resolve(0), 1000);
        
      }

      // we just resolve with how long until bday
      setTimeout(
        () =>
          resolve(Math.ceil((bday - today) / 86400000)),
        1000
      );
    });

  if (result === 0) { this.congratulateWithBirthday(); }
  else if (result > 0) { this.notifyWaitingTime(result); }
  }

不能 100% 确定这会解决你的问题,因为我看不到你调用的函数是做什么的,但我从你(ab)使用 resolve 的方式猜测你基本上想要根据现在是否是生日,在计算后调用两个函数之一。

简短回答,是的,根据您的代码,它将解析两次。这样做的原因是因为 congratulateWithBirthdaynotifyWaitingTime 不以彼此为条件,因此它们将在相同的 运行.

上被调用

如果你想避免这种情况,你应该有类似的东西

if (bday - today === 0) {
  setTimeout(() => resolve(this.congratulateWithBirthday()), 1000);
} else {
  setTimeout(() => resolve(this.notifyWaitingTime(Math.ceil((bday - today) / 86400000))), 1000);
}

此外,作为旁注,请尝试在使用 async/awaitPromise 之间做出决定。没有理由同时使用两者,这会使代码看起来很奇怪。