等待可观察的分辨率

问题描述

我已经在一个项目中工作了几个月。它的范围是在同步环境下工作,不需要http请求和其他extern异步访问。现在我必须从 http 请求中获取数据。我有许多以下代码片段:

get foo() { return this.value; }

现在,通过使用 http,我需要获取这个值,当我收到它时,只需将变量设置为响应即可。

fetchValue() { this.http.get(addr).subscribe(resp => this.value = resp); }
get foo() {  this.fetchData(); return this.value; }

这显然不起作用,因为 this.foo 将始终返回 undefined 因为事件循环仅在所有这些逻辑之后触发,因此只有在函数解析后才设置值。我也不能在一段时间内循环,因为这将导致同步执行永远不允许执行 http 请求。

有没有办法在同步循环中强制停止然后启动异步并等待它完成?或者至少等待事件循环中的一个函数完成

我无法重构代码,不仅因为它会导致代码的完全重构和代码花费的两倍多,而且还会破坏向后兼容性,这对这个项目来说是必不可少的。所以我需要 foo 在设置后返回值;我无法在代码的任何其他部分添加订阅或对 promise 的解析来处理此问题。

如果这不可能,为什么会这样?我需要清楚地解释阻碍使用此逻辑的语言范式。

解决方法

没有办法“停止”事件循环,因为它基本上是javascript的主要机制。停止事件循环实际上意味着完全停止应用程序的执行:)

为了更好地理解事件循环,我强烈建议您观看此video - 这可能是对该主题的最佳解释。

现在,让我们修复您的代码。 使用 promises 可以“等待”异步操作完成,并且由于 async/await 语法,它可以以非常漂亮的方式完成。

首先,由于您使用的是 rxjs,因此您需要将您的 http 调用转换为 Promise。这可以使用 .toPromise() 运算符完成。

async fetchValue() {
  this.value = await this.http.get(addr).toPromise();
}

请注意,我在函数名之前放置了一个 async 关键字,这允许我们在此函数中使用 await。 Await 期望正确的 promise,并会阻止它下面的代码运行,直到 promise 得到解决。

你的第二个函数现在也需要有 async/await:

async getFoo() { 
  await this.fetchData();
  return this.value;
}

Tbh,我不知道你为什么需要它,因为第一个函数实际上做了同样的工作,但是好吧,我只是想向你展示这个概念。

现在,无论何时调用 instance.getFoo(),您都需要记住它是异步的,因此您应该在调用 async/await 的函数中使用 instance.getFoo(),或者使用 .then获取价值。

使用异步/等待:

async function someMethod() {
  const foo = await instance.getFoo();
}

使用.then()

function someMethod() {
  instance.getFoo().then(foo => {
    // all the rest code here!
  })
}

同样,我建议您花一些时间观看上面的视频并阅读有关 promise 和 async/await 的文档。