JavaScript ES6类是否与异步代码库一起使用?

时间:2016-05-31 21:38:21

标签: asynchronous ecmascript-6 es6-promise es6-class

作为一种组织模式,ES6 Classes可以为异步代码提供什么。下面是ES7 async / await的示例,ES6类可以在ES7中使用异步方法或构造函数吗?

我可以这样做:

class Foo {
    async constructor() {
        let res = await getHTML();
        this.res = res
    }
}

而且,如果不是,构造函数应如何工作呢?

class Foo {
    constructor() {
        getHTML().then( function (res) {
            this.res = res
        }
    }
}

如果这些模式都不起作用,那么ES6 class中的构造函数(以及其他类)是否可以支持在对象状态下运行的任何形式的异步性?或者,它们仅用于纯粹的同步代码库吗?上面的例子都在构造函数中,但它们并不需要......将问题再推下一层......

class Foo {
    myMethod () {
      /* Can I do anything async here */
    }
}

或者,有吸气剂......

class Foo {
    get myProp() {
        /* Is there any case that this is usefully asynchronous */
    }
}

我能想到的唯一例子是在同一个方法/构造函数/ getter中并行运行某些东西,但要在结束之前解决整个问题。我只是感到困惑,因为它似乎完全异步库的推动,这只是混淆了事情。除了教科书示例,我找不到一个他们有用的应用程序。

4 个答案:

答案 0 :(得分:45)

  

我可以async constructor()

不,这是语法错误 - 就像constructor* ()一样。构造函数是一个不返回任何东西的方法(没有promise,没有生成器),它只是初始化实例。

  

而且,如果不是,构造函数应该如何工作呢

这样的构造函数根本不存在,请参阅Is it bad practice to have a constructor function return a Promise?

  

ES6类可以支持在对象状态下运行的任何形式的异步吗?或者,它们仅用于纯粹的同步代码库吗?

是的,您可以在类上使用异步方法(即使使用建议的async语法),并且getter也可以返回promise。

但是,您需要确定在某个异步进程仍处于活动状态时调用方法时应该发生什么。如果您希望它对所有操作进行排序,则应将实例的状态存储在可以链接到的序列末尾的promise中。或者,如果您想允许并行操作,最好的方法是使您的实例不可变并返回另一个实例的承诺。

答案 1 :(得分:9)

Classes用于排列异步任务的另一种方法是独占使用static methods

[1:, :]

当然,这与创建一个简单的对象文字或一个新文件并包含它没有什么不同,除了你可以更干净地class Organizer { static async foo() { const data = await this.bar(); data.key = value; return data; } static async bar() { return {foo:1, bar:2} } }; Organizer.foo(); 它。

答案 2 :(得分:9)

ECMAScript 2017旨在成为异步方法的类。

调用另一个异步或承诺返回函数是一行的!

高度表达的代码无论是延迟执行都从上到下不间断地读取

如果您有回调,替代错误处理程序,并行执行或其他未满足的需求,请在函数体中实例化promise。最好在函数体中而不是在promise执行器中使用代码,并注意没有try-catch包装回调代码:在那里做无所事事。

async方法可以返回promise,常规值或throw

Node.js人们曾经喜欢的回调api,我们现在会充满激情地讨厌:他们必须全部包含在承诺中

异步/等待的美妙之处在于错误会隐含起来

class MyClass {
  async doEverything() {
    const sumOfItAll = await http.scrapeTheInternet() +
      await new Promise((resolve, reject) =>
        http.asyncCallback((e, result) => !e ? resolve(result) : reject(e)))
    return this.resp = sumOfItAll
  }
}

如果仅限于ECMAScript 2015且没有异步,请返回承诺值:

class ES2015 {
  fetch(url) {
    return new Promise((resolve, reject) =>
      http.get(url, resolve).on('error', reject))
      .then(resp => this.resp = resp) // plain ECMAScript stores result
      .catch(e => { // optional internal error handler
        console.error(e.message)
        throw e // if errors should propagate
      })
  }
}

您正在询问此ECMAScript 2015版本,可以使用返回的promise构造对任何所需行为进行编码。

如果你真的,真的想在构造函数中执行promises,最好传入then-catch函数或提供一些回调构造,以便消费者可以对promise履行或拒绝采取行动。在构造函数中,在做实际工作之前等待nextTick / .then也是一种好习惯。

每一个承诺都需要最后的捕获或者会有麻烦

答案 3 :(得分:0)

这是一个迟到的响应,但是你的第二个例子不起作用的原因是因为上下文错误。当您将function () {}作为参数传递给Promise.prototype.then()时,函数内部的词法this将是函数本身,而不是类。这就是设置this.res似乎无效的原因:this,在这种情况下,指的是函数自己的范围。

在Javascript中有几种访问外部作用域的方法,经典的(在ES5代码中大量看到)是:

class Foo {
  constructor() {
    var _this = this

    getHTML().then(function (res) {
      _this.res = res
    })
  }
}

通过引用类this,可以在内部作用域中访问它。

ES6的做法是使用arrow functions,它不会创建新范围,而是“保留”当前范围。

class Foo {
  constructor() {
    getHTML().then(res => this.res = res)
  }
}

除了上下文问题之外,在我看来,这仍然不是一种最佳的异步模式,因为你无法知道getHTML()何时完成,或者更糟糕的是,失败了。 async functions优雅地解决了这个问题。虽然你不能创建async constructor () { ... },但你可以在构造函数中启动一个promise,并在依赖它的函数中await

Example gist类构造函数中的异步属性。