【问题标题】:How to chain async methods in javascript ES6 classes如何在 JavaScript ES6 类中链接异步方法
【发布时间】:2015-12-15 19:37:33
【问题描述】:

我想从一个类中链接方法。我对同步方法有问题,但我不知道如何使用异步方法。

比如这个类:

class Example {

  constructor() {
    this.val = 0
  }

  async () {
    setTimeout(() => {
      this.val += 1
      return this
    }, 5000)
  }

  sync () {
    this.val += 1
    return this
  }

  check () {
    console.log('checker', this.val)
    return this
  }

}

这行得通:

new Example().sync().check()
> 1

但这不起作用:

new Example().async().check()
> TypeError: Cannot read property 'check' of undefined

附:我想要链接,而不是地狱回调。

【问题讨论】:

  • 首先,async 不是 ES6,而是 ES7 的提议。
  • 您应该使用Promises,而不是试图转移this 引用。你仍然不会有那种语法(直到 ES7 中的 async/await 到达)但至少你可以避免回调地狱
  • 顺便说一句,请阅读this 了解有关提供给setTimeout 的函数的执行上下文以及为什么return this 不能像您希望的那样工作的一些信息。跨度>
  • 您需要在内部跟踪异步方法是否完成,并让check 监控它。顺便说一句,这与 ES6 或类无关(除了 promises 是 ES6,但它们在此之前也存在)。
  • 如果你想链接异步操作(就像 jQuery 对动画所做的那样),那么你可以构建一个队列(或使用承诺),每个方法都可以存储到前一个异步操作完成并触发下一个操作以及您要使用的每个异步方法和同步方法都必须在完成后通知队列。

标签: javascript node.js class ecmascript-6 chaining


【解决方案1】:

我希望您想在超时到期后致电check()。问题是分叉了,你不能立即有东西可以归还。

您可以传入check() 作为回调:

class Example {

  constructor() {
    this.val = 0
  }

  async (callback) {
    setTimeout(() => {
      this.val += 1
      callback()
    }, 5000)
  }

  sync () {
    this.val += 1
    return this
  }

  check () {
    console.log('checker', this.val)
    return this
  }

}

// execution
var ex = new Example();
ex.async(ex.check)

...或承诺

class Example {

  constructor() {
    this.val = 0
  }

  async (callback) {
    var deferred = Q.defer()
    setTimeout(() => {
      this.val += 1
      deferred.resolve();
    }, 5000)
    return deferred.promise;
  }

  sync () {
    this.val += 1
    return this
  }

  check () {
    console.log('checker', this.val)
    return this
  }

}

// execution
var ex = new Example()
ex.async().then(() => ex.check())

...或者你可以使用 ES6 生成器

【讨论】:

  • check() 不是这里的方法调用。您应该使用this 解决并执行ex => ex.check()
  • 谢谢,我正在寻找一种方法来链接这样的异步函数:new Example().async().sync().async().sunc() 等等..但是唯一的解决方案是回调(中断链,因为在匿名函数中调用 next 方法)和承诺也会中断链(因为在匿名函数内部也调用 next 方法)。所以“链”异步函数解决方案将是队列方法吗?
  • @rdbmax:问题是你不能在涉及异步的链中拥有真正的同步函数。您可以从显式附加到异步操作的回调中调用同步方法,也可以使所有方法异步并将(同步)操作放在以实例状态管理的某个队列上。
  • 我还在等待 ES6 生成器示例。 :-(
  • 对不起,破折号。我基本上把它作为个人挑战来学习它,然后太忙了。我将删除“示例即将到来”位。
【解决方案2】:

如果您只想让new Example().async().check() 工作,那么您只需在调用setTimeout 后return this。例如:

async () {
  setTimeout(() => {
    this.val += 1
  }, 5000)
  return this
}

超时内的return this 不是必需的,因为它会自行执行。那时它基本上是独立运行的。

真的,如果您希望整个事情完全异步运行,并且您能够控制某些事情发生时的流程,那么您需要使用 Promise 来实现这一点。

【讨论】:

  • 不过,这并没有达到预期的效果。
  • 什么是“预期的东西”?我觉得这个问题应该更多地出现在代码审查网站上而不是 SO。
  • 我认为他们希望在解决 5000 毫秒超时后调用 sync
  • 我预计他想在超时后运行check()
  • 我没有在问题中看到这个基础,Bergi。这就是为什么我的答案最初不是承诺的一部分。
【解决方案3】:

Promises 将最优雅地解决您要查找的问题。您可能需要安装一个 polyfill,例如 Bluebirdq

我会将您的异步方法更改为:

async() {
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            this.val += 1;
            resolve(this);
        }, 5000);
    });
}

以及您的调用代码:

new Example().async().then((instance)=>instance.check());

不幸的是,在确定 ES7 异步函数之前,如果没有某种形式的回调,就没有一种优雅的方式来做到这一点。

【讨论】:

  • ES6 包含 Promise。不需要 polyfill。
  • 嗯,确实如此...但是除非您处于完美世界或在服务器上,否则我们将需要等待 IE11 走上渡渡鸟之路...只是更容易包含一个用于 web 工作的 polyfill。
  • 嗯,这个问题确实有节点标签。为浏览器编写 ES6 似乎有点为时过早,但我想如果你不关心任何向后兼容性,它基本上可以工作......
  • 啊,没注意到那个节点标签。更有意义。
【解决方案4】:

如果您使用的是async 函数和方法,那么您就是在使用 Promise(我想您知道它们,如果不了解它们,请在继续阅读之前了解它们)。

如果您考虑等待它,则不应在异步函数内部使用setTimeout。相反,为超时创建一个承诺,最好使用这样的辅助函数:

function timeout(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms)
    });
}

现在您可以按照自己的意愿编写方法:

class Example {
  …
  async async () {
    await timeout(5000);
    this.val += 1;
    return this;
  }
  …
}

当然,作为async 函数,它不会返回实例本身,而是对它的承诺。如果您要链接,则必须在另一个异步函数中调用它,您可以在其中await 该承诺:

(async function() {
    (await (new Example().async())).check();
}());

【讨论】:

  • 糟糕,我假设 OP 是在谈论 async methods 并使用 async 作为关键字,而不是方法名称。我现在明白这不是他的意思,但我仍然认为答案很有用,所以我不会删除它。
猜你喜欢
  • 2011-03-28
  • 2016-12-26
  • 1970-01-01
  • 2021-09-15
  • 2014-03-31
  • 2018-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多