【问题标题】:javascript synchronous callbacksjavascript同步回调
【发布时间】:2016-06-11 14:58:58
【问题描述】:

我正在寻找是否有一种方法可以采用通用异步函数(例如 AJAX 或消息上的 Web Worker)并强制它同步运行。

首先——我确实需要这种行为,我知道所有关于异步回调与返回的论点——但在这种情况下,我真的需要等待回调。

如果没有可用的通用解决方案,我会选择一个纯粹在 Worker.prototype.onmessage 上工作的解决方案,因为这是这里的主要用例。

我很确定答案将是“那不可能”,但我想在投降之前检查一下。

我已经研究过 Promise 和生成器,我不想使用第三方库(我知道 Node 的 Fiber/futures)。

一个潜在的用例:

function main(){
    worker = new Worker("someWorker.js")
    var result = worker.onmessage(function(event){
        return event.data;
    })
    //wait for worker.onmessage
    return result;
}

【问题讨论】:

  • 相关jQuery问题:stackoverflow.com/q/133310/901048
  • @Blazemonger,谢谢 - 但这仅适用于 ajax 调用。不过绝对值得一提
  • 只需启动worker并将所有同步代码(取决于workers结果)放在onmessage回调中。 Promise 和生成器只是更优雅地解决了同样的问题。
  • @Vaclav,正如我所提到的 - 我真的需要回报,我正在做的项目将所有代码重写为回调是不可行的

标签: javascript synchronization


【解决方案1】:

如果你想保持函数的同步流,生成器函数是唯一可能的解决方案。您将发送所有异步任务,例如 var result = yield new Worker('someWorker.js')

function* main 之外,您将获得带有mainFn.next().valueworker,然后附加onmessage 侦听器,该侦听器会将解析的数据返回到function* main,并且该功能将恢复。

完整的生成器示例如下所示

// write function as generator
function* main () {
    var result = yield new Worker("someWorker.js");
    return result;
}

// instantiate the generator and get the first yield value
var mainFn = main()
  , worker = mainFn.next().value

// set onmessage listener, which is callback, that sends data back to *main()
worker.onmessage = function(event) {
    mainFn.next(event.data);
}

这样您的main() 函数将保持与原始形式几乎相似,因此您可以重用原始代码,但您需要编写周边逻辑,这并不简单,而且无论如何都会使用回调。

您似乎知道什么是生成器,并且它在浏览器中并未得到广泛支持,因此如果您想在网页上运行此代码,您将需要 ES6 转译器Babel

【讨论】:

  • 这不起作用,因为随后对mainFn.next() 的调用不会等待worker.onmessage
  • @ZackNewsham 第一次调用next() 会从main() 产生Worker,第二次调用next() 会将event.data 传递给main(),它将Worker 替换为@ 987654340@ 和简历main()。对mainFn.next() 的第二次调用放在回调中,因此它肯定会等待消息事件,但您的工作人员可能会返回多条消息。在这种情况下,您希望将消息累积到某个变量,然后在数据完成后,将其传递回 main()mainFn.next(completeData)
  • 我尝试了一个普通的工作人员,可能是生成器在不同的浏览器中实现不同(我使用的是 Chrome)。此外,我在 Meteor 中使用它,它在部署之前编译代码 - 所以它可能会搞砸。
  • 我花了一些时间来理解它——它确实有效,但遗憾的是它并没有比将代码编译成回调更干净——因为我必须重组代码以使用生成器,我'希望我可以简单地调用生成器,并让它处理所有下一个,等等 - 然后返回最终结果。
  • @Zack Newsham 生成器的棘手之处在于它们与外部世界是异步的。您可以或多或少地使用旧代码,但您需要将其包装在相当复杂的处理逻辑中,这将解析所有产生的值以及最终的return,它也像 yield 一样工作(注意result不是从for ... of 产生的),然后将此异步结果传递给其他生成器等,因此最终您可能会意识到,完全重写为回调并不是一个坏主意。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-02
  • 2015-07-30
  • 2019-06-08
  • 1970-01-01
  • 1970-01-01
  • 2010-10-25
  • 1970-01-01
相关资源
最近更新 更多