问题描述
我已经在一个项目中工作了几个月。它的范围是在同步环境下工作,不需要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 的文档。