【问题标题】:Strange async/await behaviour in a class类中奇怪的异步/等待行为
【发布时间】:2017-09-13 02:12:57
【问题描述】:

节点 7.9.0

这是场景:

class TestClass {
  constructor() {
    const x = await this.asyncFunc()
    console.log(x)
  }
  async asyncFunc() {
    return new Promise((accept) => {
      setTimeout(() => accept("done"), 1000)
    })
  }
}
new TestClass()

第3行的错误是Unexpected token this

好的,所以我就这样结束了...const x = await (this.asyncFunc())

现在我得到await is not defined

这让我觉得节点 7.9.0 不知道等待/同步,尽管 http://node.green/ 告诉我它受支持并且它的示例运行得很好。

(function(){
(async function (){
  await Promise.resolve();
  var a1 = await new Promise(function(resolve) { setTimeout(resolve,800,"foo"); });
  var a2 = await new Promise(function(resolve) { setTimeout(resolve,800,"bar"); });
  if (a1 + a2 === "foobar") {
    console.log("passed")
  }
}());
})()

【问题讨论】:

  • 请注意,在示例中,awaitasync 函数中使用。你的代码在这方面是不同的。
  • ...所以你需要一个异步构造函数...
  • 你不能在构造函数中使用await。但是,您可以使用this.asyncFunc().then(console.log)。但是,通常应避免在构造函数中进行异步处理。
  • 您可能想签出this

标签: javascript node.js asynchronous async-await


【解决方案1】:

恕我直言,在构造函数中使用 await 是不明智的。构造函数应该是轻量级的。构造函数不应失败。

MSDN about constructors

考虑提供简单的、理想情况下的默认构造函数。一个简单的 构造函数的参数数量很少,所有参数 是原始类型或枚举。

考虑使用静态工厂 方法而不是构造函数,如果需要的语义 操作不直接映射到新实例的构造, 或者如果遵循构造函数设计指南感觉不自然。

一个好的解决方案是创建一个静态异步工厂方法,该方法将调用一个简单的私有构造函数并调用您的私有 asyncfunc。

这样,人们可以通过调用您的静态异步工厂方法来创建您的类的实例的唯一方法,因此您可以确定您的 asyncFunc 已被调用。

好消息是:这一切都没有诡计

我对JAVA不是很熟悉,下面是C#,但我想你会明白的

class TestClass
{
    public async Task<TestClass> CreateAsync()
    {
        TestClass instance = new TestClass(); // lightWeight
        Promise p = await instance.AsyncFunc();
        // do what you need to do with your Promise
        Console.Log(...)
        return instance;
    }

    // private constructor: only CreateAsync can call it:
    private TestClass()
    {
        // make it lightweight
    }

    public async Task<Promise> AsyncFunc()
    {
        return new Promise((accept) => 
        {
            setTimeout(() => accept("done"), 1000)
        });
    }
}

用法。

而不是

TestClass myObject = new TestClass();

你会这样做:

 TestClass myObject = await TestClass.Creat();

您的调用将是异步的,构造函数是轻量级的,并且您确定您的 asyncFunc 已被调用并等待。

【讨论】:

    【解决方案2】:

    添加异步启动功能并使用它来解决问题:

    所以最初的例子可以用异步启动函数来修复:

    class TestClass {
      constructor() {
        this.start()
      }
      async start() {
        const x = await this.asyncFunc1()
        console.log(x)
      }
      async asyncFunc1() {
        return new Promise((accept) => {
          setTimeout(() => accept("done"), 1000)
        })
      }
    }
    new TestClass()
    

    如果你想在 asyncFunc1 中进一步调用 await,你也需要让 promise 函数异步...

    class TestClass {
      constructor() {
        this.start()
      }
      async start() {
        const x = await this.asyncFunc1()
        console.log(x)
      }
      async asyncFunc1() {
        return new Promise(async (accept) => {
          const x = await this.asyncFunc2()
          accept(x)
        })
      }
      async asyncFunc2() {
        return new Promise((accept) => {
          accept("done")
        })
      }
    }
    new TestClass()
    

    【讨论】:

    • 事情是对象被构造并且它的引用返回给调用者而无需等待启动函数运行。例如,调用者可能开始使用其他尚未准备好的成员函数。最好让构造函数初始化对象(即使用默认值或传入值)并让调用者自己调用'start(..)'。
    猜你喜欢
    • 1970-01-01
    • 2018-07-18
    • 2021-11-14
    • 1970-01-01
    • 2023-02-21
    • 2022-01-08
    • 1970-01-01
    • 2021-11-18
    • 2018-09-21
    相关资源
    最近更新 更多