【问题标题】:Rejecting a Promise by passing a Promise通过传递一个 Promise 来拒绝一个 Promise
【发布时间】:2018-05-25 10:26:13
【问题描述】:

为什么 resolveing 承诺正确地等待 someOtherPromise 完成,而 reject 却没有?运行以下代码示例并检查 console.log 输出。我预计“myFailingPromise denied”消息会在 2000 毫秒后显示,就像“myPromise resolved”一样。

let someOtherPromise = (previousPromise) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(previousPromise + ' => someOtherPromise after 2000ms');
      resolve('someOtherPromise');
    }, 2000);
  });
}

let myPromise = () => {
  return new Promise((resolve, reject) => {
    resolve(someOtherPromise('myPromise'));
  });
};

let myFailingPromise = () => {
  return new Promise((resolve, reject) => {
    reject(someOtherPromise('myFailingPromise'));
  });
};

myPromise().then((val) => {
  // this is executed after `someOtherPromise` resolves.
  console.log('myPromise resolved');
}).catch((err) => {
  console.log('myPromise rejected');
});

myFailingPromise().then((val) => {
  // this is executed after `someOtherPromise` resolves.
  console.log('myFailingPromise resolved');
}).catch((err) => {
  console.log('myFailingPromise rejected');
});

我知道可以通过在第二个示例中使用 someOtherPromise.then(reject) 来实现预期的行为,但我的问题是为什么不能将承诺作为 reject 的参数,因为它适用于 resolve

【问题讨论】:

  • 这就是resolve and reject 的工作原理。 resolve is not fulfill(很遗憾)。
  • 您在 myPromise 中的新 Promise 会立即使用 someOtherPromise 解析。所以myPromise().then() 实际上只是someOtherPromise 的成功处理程序。您想在这里实现什么目标?
  • 我用适当的样本更新了问题

标签: javascript promise es6-promise


【解决方案1】:

当你解决一个promise A时,如果你解决它的值是一个promise B,那么你的promise A将匹配promise B的状态。

然而,当你拒绝一个承诺时,你只给出一个理由,不管这个理由看起来是否像一个承诺。

您需要做的是在这两种情况下都使用someOtherPromise 解决。

如果你想等待第一个承诺并拒绝,你可以这样做:

let myFailingPromise = () => {
  return new Promise((resolve, reject) => {
    someOtherPromise.then(reject);
  });
};

【讨论】:

  • resolveing 这两种情况都不是正确的方法,因为 catch 正在等待失败的情况。如果我想用一个承诺来拒绝那个承诺,我必须打电话给someOtherPromise.then(reject)(这可行)。我的问题是:为什么不支持reject(someOtherPromise)
  • @Flame 在您的问题中更新您的美国案例。这对我来说听起来像是一个 XY 问题。你为什么要用另一个 Promise 拒绝一个 Promise(设计不支持)?
  • @k0pernikus 我只是想拒绝等待通过的承诺履行的承诺。如果答案是“它不受设计支持”或“拒绝不应该包含承诺”,那么这并不能回答问题,因为您基本上是在说“你不能因为你不能”。
  • resolve(someOtherPromise.then(() => throw new Error("reject")))
  • 您更新的答案调用 then(reject()) 但它应该是 then(reject) 否则我相信它会立即执行
【解决方案2】:

拒绝只接受reason 以突出显示错误。不是另一个承诺。您可以使用另一个相同类型的 Promise 解决一个 Promise,但您只会看到最后一个 Promise 的成功案例。

看看这个改编的实现:

const someOtherPromise = new Promise((resolve, _) => {
    resolve("I am a success");
});
const failingPromise = new Promise((_, reject) => {
    reject("I failed for a reason");
});

someOtherPromise
    .then((result) => {
            console.log("some other promise resolves", result);
            failingPromise
                .then((success) => {
                    console.log("never called");
                })
                .catch((reason) => {
                    console.error("failing promise rejects", reason);
                });
        }
    )
    .catch((error) => {
        console.error("also never called", error);
    });

这是then-able 方法来等待导致回调地狱的其他承诺。这就是为什么你也可以使用 async / await 语法:

const app = async () => {
        try {
            const success1 = await someOtherPromise; // will succeed
            console.log(success1);
            const success2 = await failingPromise; // never succceds
            console.log(success2); // never be reached
        } catch (e) {
            return Promise.reject(e); // catches the error of failing promise and rethrows it, redundant but here showcases error handling
        }
    }
;

app()
    .then(() => {
        console.log("never be reached because of failing promise");
    })
    .catch(console.error);

【讨论】:

  • 当 Promise 支持 rejection 并以 Promise 作为参数时,是否会出现本质上的错误?我想知道为什么它不遵循resolve 规范。
  • 您可以使用任何类型的resolve。它可以是字符串、数字、对象,也可以是一个 Promise 或 Promise 的集合——无论你想作为 Promise 的成功案例。拒绝只处理一个原因,即字符串消息或Error。拒绝不应包含其他 Promise。
  • @Flame 如果reject 同化了promise,那么它与resolve 有什么不同呢? (其实reject根本没有必要,我们只能用resolve,用resolve(Promise.fulfill(value))resolve(Promise.reject(reason))来区分成功和错误的情况。)
  • 我设想resolve(myPromise) 将导致then()catch 随后被调用(取决于myPromise 结果),但reject(myPromise) 将导致catch() 被调用后来叫了。请注意,在这两种情况下,它都应该等待 myPromise 成功/失败
【解决方案3】:

关于您更新的超时问题,您可以执行以下操作以始终等待另一个承诺:

const otherPromise = async (willBeSuccesful: boolean) => {
    console.log("started timer for case", willBeSuccesful);

    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log("resolve timer for case", willBeSuccesful);

            const successValue = "Fnord"; // whatever you want

            return willBeSuccesful
                ? resolve(successValue)
                : reject("this other promise failed because of reasons"); // only provide a reason, not another promise
        });
    };
};

const alwaysWaitForOtherPromiseThenRejectAnyway = async (otherPromise) => {
    try {
        const success = await otherPromise; // always waits 2 seconds, not matter
        console.log("other promises succeeded with value", success);
    } catch (e) {
        return Promise.reject(e); // passing through reason, redundant, only to showcase
    }

    return Promise.reject("reason why this promise failed"); // only happens after otherPromise was resolved, you could swallow that error and fail here or resolve here as well
};

const succeedingPromise = otherPromise(true);
const failingPromise = otherPromise(false);

alwaysWaitForOtherPromiseThenRejectAnyway(succeedingPromise)
    .catch((reason) => console.error(reason)); // fail after waiting for success of other promise

alwaysWaitForOtherPromiseThenRejectAnyway(failingPromise)
    .catch((reason) => console.error(reason)); // will fail as soon as otherPromise fails

在拒绝发生之前它总是会等待超时。拒绝会有不同的原因。输出将是:

started timer for case true
started timer for case false
resolve timer for case true
resolve timer for case false
other promises succeeded with value Fnord
reason why this promise failed
this other promise failed because of reasons

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-11
    • 1970-01-01
    • 2019-11-22
    • 2016-12-03
    • 2015-02-11
    相关资源
    最近更新 更多