【问题标题】:Typescript async/await structuring issue打字稿异步/等待结构问题
【发布时间】:2016-10-20 05:53:46
【问题描述】:

我一直在我的 Typescript 项目(针对 es6)中研究一个有趣的问题。基本上,我希望能够以某种未确定的顺序快速定义许多不同系列的用户输入“页面”,以及前一页的结果可能对下一个“页面”的构建有影响,也可能不影响。

因此,我将每个页面视为由函数(此处为 getPromise1() 等)构造的 Promise,一旦用户输入完成,该函数就会解析为结果。然后我使用 async/await 按顺序创建页面。

async process() {
    let result1 = await this.getPromise1();

    let result2 = await this.getPromise2(result1.someData);

    //etc...

    this.commit();
}

这很好用,但是我遇到了障碍。页面序列可以在任何阶段通过用户输入取消,因此此时需要中止构建。问题是,在每个阶段检查是否取消变得令人厌烦和不雅,而且我强烈地觉得走错路了。

async process() {
    let result1 = await this.getPromise1();
    if (result1.cancelled) {
        this.revert();
        return;
    }


    let result2 = await this.getPromise2(result1.someData);
    if (result2.cancelled) {
        this.revert();
        return;
    }

    //etc...

    this.commit();
}

我哪里出错了?我是否为这种设置使用了完全不正确的模式?有没有更优雅的方法来处理这种方法?还是真的没有更好的方法来处理这样的事情?

【问题讨论】:

  • 仅供参考,async/await 不是 ES7 的一部分。

标签: typescript async-await es6-promise


【解决方案1】:

一种可能的解决方案是让您的“页面”拒绝他们的承诺(即 throw 错误),以便您可以在 process 函数中 catch 错误。

class App {

    async process() {
        try {
            let result1 = await this.getPromise1();

            let result2 = await this.getPromise2(result1.someData);

            //etc...

            this.commit();
        } catch (e) {
            this.revert();
        }
    }

    async getPromise1() {
        return {someData: 'foo'};
    }

    async getPromise2({someData}) {
        throw new Error('cancelled');
    }

}

【讨论】:

  • 我想到了这一点,但是我不希望将抛出/捕获异常作为运行软件的常规部分 - 它只是感觉不对,我认为它会对性能产生重大影响。跨度>
  • @Daniel 同意,异常只能用于处理异常情况,不能用于“常规”控制流。不幸的是,除了在您的 OP 中手动处理它之外,我想不出其他方法。 :-/
【解决方案2】:

由于这是一个序列,并且您总是在您的承诺上测试 cancelled,因此您可以创建一个您承诺的所有扩展的接口

interface Prom {
    cancelled?: boolean
}

然后运行序列

const seq: Prom[] = [this.getPromise1(), this.getPromise2(),...]

for (let p of seq) {
    const res = await p
    if (res.cancelled) {
        return this.revert()
    }
}

或者,如果您向reject 做出承诺,而不是将结果设置为cancelled(我会这样做),您可以从Promise.all 的快速失败行为中受益:

try {
    await Promise.all([this.getPromise1(), this.getPromise2(),...])
catch(e) {
    //a promise was rejected
}

在使用await 时无法真正避免处理异常。 所以如果不想处理异常,就用then

Promise.all([this.getPromise1(), this.getPromise2(),...]).then(
    () => { //success },
    (reason) => { // failure }
)

【讨论】:

  • 感谢您的回答!不幸的是,这不允许我需要的非常重要的功能,即使用一个承诺的结果作为下一个承诺的输入的能力。至于异常处理,我不妨碍处理异常,但我想避免在非异常情况下抛出它们。
猜你喜欢
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-08
  • 2018-05-03
  • 1970-01-01
  • 2019-03-18
  • 2017-05-11
  • 2023-02-21
相关资源
最近更新 更多