如何等待承诺被解决?

35
我正在处理一个需要特定函数为同步的Node.js框架,但我需要异步访问才能获取值。在理想情况下,我可以返回Promise,但我不能这样做。为了快速解决问题,我创建了以下方法:
exports.synchronizePromise = function(promise) {
    var value;
    promise.then(function(promiseValue) {
        value = promiseValue;
    });
    while (!value) {} // Wait for promise to resolve
    console.log("DONE: " + value); // Never reached
    return value;
};

但我遇到了错误。 有没有办法实现我需要的功能?


4
承诺并不能奇迹般地使事情同步,它们只是使一些异步过程更容易编码和管理的工具,并通过多个步骤实现。不要使用循环尝试冻结,只需将同步的内容拆分成两部分来解决上游问题。 - dandavis
2
@dandavis 我考虑过对我正在使用的框架进行提交,使得该函数可以是异步的,但它被调用的地方太多了,99%的时间里,它不需要是异步的。修复上游并不是一个真正的选项。 - sinθ
在调度进程后,您可以立即返回一个GUID,在进程完成时,在您的数据/ DOM中查找GUID并替换为实际值。 - dandavis
1
Javascript(和NodeJS)只有一个线程,“while(!value){}”会让程序冻结!(正如@dandavis所说)。您必须先获取值,然后在拥有它时执行同步部分。 - Matthew Wilcoxson
这是我用来解决类似问题的方法,但我的Node.js框架不适用于高性能Web服务器 → http://stackoverflow.com/search?q=I%27ve+recently+created+simpler+abstraction+WaitFor+to+call+async+functions+in+sync+mode - xmojmr
显示剩余5条评论
3个回答

4

考虑到Node默认只能单线程运行,所以没有简单的解决方法。但是有一种方法可以解决问题,就是基于生成器/纤程,可以为Node添加一种并发执行的方式。其中有一种waitfor 实现就是基于此。


3
在Q中,如果你有一个已经解决的Promise,你可以使用inspect方法来获取其值。
exports.synchronizePromise = function(promise) {
  var i = promise.inspect();
    if (i.state === "rejected") {
      throw i.reason;
    } else if (i.state === "fulfilled") {
      return i.value;
    } else {
      throw new Error("attempt to synchronize pending promise")
    }
};

然而,如果承诺处于挂起状态,它就是真正的异步操作,你的问题就没有意义了,并且该函数会抛出一个错误。

谢谢。我忘了NodeJs是单线程的,所以我以为我可以等到它解决了。 - sinθ
@sinθ,你可以等待直到它被解决,这就是.then的作用,只需将该函数调用放在.then块内即可。 - Benjamin Gruenbaum
检查已解决的 Promise 的值在这里有什么帮助? - user663031

-4

承诺是异步的。它们代表着未来的价值——一个在未来1毫秒、1分钟、1天、1年或永远可用的价值。根据定义,除了时光机之外,没有办法“强制”它们解决。

如果您的上游逻辑建立在同步性的前提下,但由于某种原因,它所依赖的东西现在是异步的,那么您必须重构上游组件以异步方式运行。没有其他选择。

如果您的框架“要求某个函数是同步的”,而该函数不是或不能是同步的,则该框架设计得很差,无法使用,或者至少对您的问题无法使用。


14
虽然这是一个有道理的观点,但它离实际问题有些偏题,实际问题是如何解决承诺。解决承诺的价值超出了这个特定的用例。 - Siddhu
@siddhuwarrier 不太确定你想表达什么。基本上,你无法解决一个 Promise;Promise 会自行解决(或不解决),你所能做的就是等待它发生。或者我有什么遗漏吗?你所说的“解决 Promise”是什么意思? - user663031
我所指的是一种机制,可以等待异步操作的结果解决。例如,在Scala中,` val f = Future { ... };f.map { item => //使用未来的结果执行操作 }.recover { //处理错误 };Await.result(f, 10000毫秒); `这样做的一个用例是,未来本身可能会并行执行多个线程以产生结果,而主线程则等待它完成。 - Siddhu
1
虽然JavaScript的Promise可能不支持此功能,但这并不意味着没有任何好的理由需要一个线程来阻塞异步操作的结果。 - Siddhu
2
大多数基于Promise的异步框架都支持线程加入/阻塞等待,但ES6不支持是ECMA(以及部分Node并发模型)做出的决定,而不是某种哲学上的不可能,因此有许多有效的用例。 - Arkadiy Kukarkin
在网络传输中,顺序往往很重要。如果您正在构建一个发送网络流量的服务器端应用程序,当然可以在解决问题时异步发送响应。但是,告诉另一端的客户端找出它解决的顺序以拼凑传输是不可接受的。因此,在某些时候,您需要等待所有内容都按顺序解决,以拼凑您需要发送的数据。 - Steve Buzonas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接