是否有可能异步等待-流利的构建器方法

时间:2019-03-08 10:18:44

标签: javascript asynchronous

这是我成长的道路:回调,承诺,异步/等待。我谨记一个模式-流利的构建器,对解释器来说看起来更多。我想将异步/等待与解释器混合在一起。可能吗?我觉得这是不可能的。但我可以确切地定义原因。 我有:

  after(async () => {
    await shellContainer.uninstall()
    await shellContainer.dispose()
  })

我很感兴趣:

after(async () => {
    await shellContainer
      .uninstall()
      .dispose()
  })

致谢。

3 个答案:

答案 0 :(得分:1)

如果更改.uninstall以返回实例(shellContainer),同时将其Promise分配给实例的属性,并在链式调用中检索该Promise,则可以:

class ShellContainer {
  uninstall() {
    // Chain or construct a Promise and assign the result to a property of the instance:
    this.uninstProm = new Promise((resolve, reject) => {
      // do stuff
    });
    return this;
  }
  dispose() {
    return this.uninstProm.then(() => {
      // do stuff
    });
  }
}

然后

await shellContainer
  .uninstall()
  .dispose()

dispose完成后将解决。

请注意,使用这种方法,单独调用uninstall 可能会导致意外行为,因为.uninsall将同步返回实例,而不是Promise。您可能会考虑使用一个额外的参数或其他方式来表明您是否希望将uninstall调用与其他方式链接起来,或者是否希望直接返回Promise,例如

class ShellContainer {
  uninstall(doChain) {
    // Chain or construct a Promise and assign the result to a property of the instance:
    this.uninstProm = new Promise((resolve, reject) => {
      // do stuff
    });
    return doChain ? this : this.uninstProm;
  }
  dispose() {
    return this.uninstProm.then(() => {
      // do stuff
    });
  }
}

  await shellContainer
    .uninstall(true)
    .dispose()

或者只是

await shellContainer.uninstall(); // no doChain argument

但是,如果只存在一个 承诺,那么在许多情况下对await的需求就不多了-它可能根本无法使代码更清晰。例如

after(async () => {
  await shellContainer
    .uninstall()
    .dispose()
})

等同于

after(() => shellContainer
              .uninstall()
              .dispose()
);

答案 1 :(得分:1)

要分开考虑,可以引入专用的builder来实现流畅的界面。

这样,您只需要从最终的build方法中返回一个Promise,就可以使事情变得简单得多。

以下是一个相当粗糙但实用的示例:

class ShellContainer
{
  uninstall() {
    return new Promise(resolve => {
      setTimeout(() => {
        console.log('uninstalled');
        resolve();
      }, 400 + Math.random() * 600);
    });
  }

  dispose() {
    return new Promise(resolve => {
      setTimeout(() => {
        console.log('disposed');
        resolve();
      }, 400 + Math.random() * 600);
    });
  }
}

class ShellContainerBuilder
{
  container;
  plan;

  constructor() {
    this.reset();
  }

  reset() {
    this.container = new ShellContainer();
    this.plan = () => Promise.resolve();
  }

  stage(op) {
    this.plan = ((prev) => () => prev().then(op))(this.plan);
  }

  uninstall() {
    this.stage(() => this.container.uninstall());
    return this;
  }

  dispose() {
    this.stage(() => this.container.dispose());
    return this;
  }

  build() {
    return this.plan().then(() => this.container);
  }
}

(async () => {
  console.log('starting w/o builder:');
  const shellContainer1 = new ShellContainer();
  await shellContainer1.uninstall();
  await shellContainer1.dispose();
  console.log('w/o builder done.');

  console.log('starting w/ builder:');
  const shellContainer2 = await (new ShellContainerBuilder()).uninstall().dispose().build();
  console.log(shellContainer2);
  console.log('w/ builder done.');
})();

答案 2 :(得分:0)

实现Fluent构建器的模式-解释器不适合Async / Await。因为等待是对每个操作应用的。在链的中间没有这样的语法来处理异步。要处理异步操作,您应该拆分链接并由await运算符包装操作,就像在第一个代码段中一样。