【问题标题】:Meteor._wrapAsync causes Meteor to be unresponsiveMeteor._wrapAsync 导致 Meteor 无响应
【发布时间】:2014-04-10 17:13:45
【问题描述】:

我正在使用Meteor._wrapAsync 强制只调用一次函数writeMeLater 随时执行。如果在 1 秒内拨打了 10 次对writeMeLater 的呼叫,则其他 9 次呼叫应按顺序排队。

要检查writeMeLater 是否同步运行,Logs 集合中的timestamp 字段应间隔 1 秒。

问题:使用以下代码,只执行了对writeMeLater 的第一次调用,其他9 个似乎没有运行。为什么会这样?

服务器代码:

writeMeLater = function(data) {
    console.log('writeMeLater: ', data)

    // simulate taking 1 second to complete
    Meteor.setTimeout(function() {
        Logs.insert({data: data, timestamp: new Date().getTime()})
    }, 1 * 1000)
}

writeMeLaterSync = Meteor._wrapAsync(writeMeLater)


// simulate calling the function many times real quick
for(var i=0; i<10; i++) {
    console.log('Loop: ', i)
    writeMeLaterSync(i)
}

输出:

=> Meteor server running on: http://localhost:4000/
I20140119-11:04:17.300(8)? Loop:  0
I20140119-11:04:17.394(8)? writeMeLater:  0

使用writeMeLater 的替代版本,我遇到了同样的问题:

writeMeLater = function(data) {
    console.log('writeMeLater: ', data)
    setTimeout(Meteor.bindEnvironment( function() {
        Logs.insert({data: data, timestamp: new Date().getTime()})
    }), 1 * 1000)
}

【问题讨论】:

    标签: javascript node.js meteor


    【解决方案1】:

    TL;DR - 您的 writeMeLater 函数需要采用 callback 参数。


    NodeJS 经典的异步函数通常有这个签名:

    function async(params..., callback) {
        try {
            var result = compute(params);
            callback(null,result);
        }
        catch {
            callback("something went wrong", null);
        }
    }
    

    它们采用任意数量的参数,最后一个是在计算准备好时运行的回调,使用 2 个参数调用:error 如果一切正常,则为 null,当然还有 result

    Meteor._wrapAsync 期望获得具有此签名的函数以返回新的伪同步函数。 Meteor“同步”函数允许您以同步样式编写代码,但它们并不像 NodeJS fs.readFileSync 那样真正同步,例如,它阻塞事件循环直到它完成(通常这很糟糕,除非您正在编写命令 - line 应用程序,而 Meteor 不是这种情况)。

    注意:在 Meteor 中使用 NodeJS fs *Sync 函数是不好的,因为你可能会被骗以为它们是“Meteor 同步”的,但事实并非如此,它们会阻塞你的整个节点进程,直到它们完成!您应该使用用 Meteor._wrapAsync 包装的 fs 异步函数。

    Meteor._wrapAsync 的简化克隆如下所示:

    var wrapAsync=function(asyncFunc) {
        // return a function who appears to run synchronously thanks to fibers/future
        return function() {
            var future = new Future();
            // take the arguments...
            var args = arguments;
            // ...and append our callback at the end
            Array.prototype.push.call(args, function(error, result) {
                if (error) {
                    throw error;
                }
                // our callback calls future.return which unblocks future.wait
                future.return(result);
            });
            // call the async func with computed args
            asyncFunc.apply(null, args);
            // wait until future.return is called
            return future.wait();
        };
    };
    

    有一个 Future.wrap 可以做到这一点,Meteor._wrapAsync 有点复杂,因为它使用 Meteor.bindEnvironment 处理 Meteor 环境变量。

    Fibers 和 Futures 有点超出范围,所以我不会深入研究它们,请务必查看 eventedmind.com 有关该主题的视频。

    介绍纤维 - https://www.eventedmind.com/feed/BmG9WmSsdzChk8Pye

    使用期货 - https://www.eventedmind.com/feed/kXR6nWTKNctKariSY

    Meteor._wrapAsync - https://www.eventedmind.com/feed/Ww3rQrHJo8FLgK7FF

    现在您已经了解了如何在 Meteor 中封装异步函数,让我们来修复您的代码。

    如果你的异步函数没有将回调作为最后一个参数,它不会调用它(很明显),并且我们在包装函数中传递给它的回调也不会触发,这意味着 future.return 赢了'不要被调用,这就是为什么你的程序首先被阻止的原因!

    您只需重写writeMeLater 即可将回调作为最终参数:

    var writeMeLater = function(data, callback){
        console.log('writeMeLater: ', data);
        // simulate taking 1 second to complete
        Meteor.setTimeout(function() {
            Logs.insert({
                data:data,
                timestamp:new Date().getTime()
            });
            callback(null, "done processing " + data);
        }, 1 * 1000);
    };
    

    你可以走了!

    【讨论】:

    • 不确定这是否应该是一个单独的问题:如果有 2 个客户端发出相同的 Meteor.call('writeMeLater'),则当前来自一个客户端的呼叫不会阻止来自另一个客户端的呼叫,并阻止来自同一个客户。来自第一个客户端的呼叫是否有可能阻止来自第二个客户端的呼叫?
    • 这些 URL 似乎已损坏,_wrapAsync() 可能会被 Async 库取代:meteorhacks.com/improved-async-utilities-in-meteor-npm.html
    猜你喜欢
    • 2014-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-07
    • 1970-01-01
    • 2016-08-07
    相关资源
    最近更新 更多