【问题标题】:Callbacks that don't block不阻塞的回调
【发布时间】:2013-07-19 15:53:09
【问题描述】:

我想写一个函数,它接受一个回调并在函数完成后调用它。

这很简单:

var callback = function (ref) {
    var i = 1337;
    while (i--) {
        console.log(ref, 'callback');
    }
};

var someFoo = function (ref, callback) {
    console.log(ref, 'self');

    callback(ref);
}

someFoo('one', callback); // 1
someFoo('two', callback); // 2

但在这里我遇到了这个问题:首先someFoo 调用阻塞,直到 allback 完成。这意味着这段代码等价于这个(阻塞直到每个函数完成):

someFoo('one');
callback('one');
someFoo('two');
callback('two');

现在的问题是:如何使回调调用异步?

【问题讨论】:

    标签: javascript asynchronous callback


    【解决方案1】:

    变化:

    callback(ref);
    

    收件人:

    setTimeout(function(){ callback(ref); }, 0);
    

    或者,由于您正在编写 chrome 扩展,因此不必担心旧版浏览器,您可以使用bind

    setTimeout(callback.bind(null, ref), 0);
    

    【讨论】:

    • 这看起来很脏。还有一些“官方”的方式吗?
    • @WaleryStrauch 不,唯一的其他方法会更脏。
    • 这不是一个肮脏的黑客。正如 Mike Thompson 所回答的,JavaScript 代码是同步的。 “异步”执行的唯一来源是外部影响(例如浏览器响应事件或计时器)
    【解决方案2】:

    在浏览器中实现的 JavaScript 是单线程的,因此您无法进行真正的异步调用。你可以做的是这样来近似:

    setTimeout(function() {
        callback(ref);
    }, 1000);
    

    其中 1000 是以毫秒为单位的 1 秒(根据需要进一步延迟)。但是,由于它是单线程的,回调仍然会阻塞其他正在运行的代码。

    新浏览器支持web workers,但使用网络工作者来近似线程化会给您留下许多旧浏览器无法使用的代码,而且即使现在并非所有新浏览器都支持完整规范。

    【讨论】:

    • 在我的情况下它是 chrome 扩展,所以我不关心 IE(或旧版浏览器)
    • 我认为您选择的答案对您没有帮助,因为它所做的只是在同一线程中的给定时间任意执行一段代码。您可能只需要硬着头皮继续调整,直到找到更明显的同步运行速度。
    • @MikeThomsen setTimeout 保证回调在当前执行流程完成后的某个时间执行。这就是 Javascript 事件循环的工作方式。它不是任意的,它不会阻塞任何其他正在运行的代码,因为它不会在任何其他代码(已经启动的)完成之前运行。
    猜你喜欢
    • 2012-08-17
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-18
    • 1970-01-01
    相关资源
    最近更新 更多