【问题标题】:RequireJS module for SignalRSignalR 的 RequireJS 模块
【发布时间】:2013-06-06 20:19:23
【问题描述】:

我没有将我的代码复制并粘贴到这里,而是将其上传到github。 RequireJS 模块确实依赖于 jquery.signalr,并且在 tern 上依赖于 jquery,但也依赖于 /signalr/hubs 中保存的 javascript。 Require.Config 有一些配置。

基本上,在您第一次加载页面时,会在 signalr 中与集线器建立连接,然后执行“服务器端”代码并执行所需的操作。当您刷新页面时,它不会。调用所有客户端代码,例如:

var myViewModel = new MyViewMode();
myViewModel.init();

在你的 init 方法中你有

var connection = $.connection.myHub;
this.init = function() {
  connection.server.myMethod();
}

这将继续

public MyHub : Hub 
{
    public void MyMethod()
    {
        Client.Request.populateSomeInformation() // I think it's request but I'm doing this from memory!
    }
}

然后调用

connection.client.populateSomeInformation = function () { .. )

但不叫这个:(

看起来好像已经建立了连接(使用旧的 console.log() 来查看它的输出)并且确实在调试它在集线器内执行代码但没有做出响应的项目回到javascript。

这么棒的互联网人,我哪里错了?在尝试重新启动之前是否需要检查$.connection.hub.start(); 的状态?

啤酒时间:)

【问题讨论】:

    标签: requirejs signalr


    【解决方案1】:

    我认为应该是的

    connection.client.populateSomeInformation = function () { .. )
    

    (不是连接服务器)

    http://www.asp.net/signalr/overview/hubs-api/hubs-api-guide-javascript-client#callclient


    (对你现在在 github 上的代码的观察)

    var isLoaded = false;
    
    // ... some code that doesn't change isLoaded ...
    
    if (isLoaded == false) {       
        scrollIntervalId = window.setInterval(function () {
            signalRLoaded();
        }, 30);
    
    }
    

    我认为isLoaded 在这一点上总是错误的。不确定您打算这样做。

    var connection = $.connection.hub.start();
    

    我认为您不应该在定义任何客户端函数之前打开连接。我没有看到这里定义了任何客户端函数,所以也许你正在其他地方这样做?除了服务器尝试调用尚未定义的客户端函数之外,我不知道这是否真的很重要......

    function SignalRReady(callback) {
        if (isLoaded) {
            callback(connection);
        } else {
            readyCalls = callback;
        }
    
        return SignalRReady;
    }
    
    SignalRReady.version = "1.0.0";
    
    SignalRReady.load = function(name, request, onLoad, config) {
        if (config.isBuild) {
            onLoad();
        } else {
            SignalRReady(onLoad);
        }
    };
    
    return SignalRReady;
    

    我对这段代码感到困惑,可能是因为我看不到它是如何被使用的。这是对单例的尝试吗?我看到 SignalRReady 是为模块返回的“类”。您并没有真正返回一个对象,而是返回了一个构造函数,这意味着您正在其他地方实例化它,例如

    define(['SignalRReady'], function(sigR)
    {
        var srr = new sigR();
    });
    

    但是你定义了 load 函数,它调用构造函数,这看起来很奇怪。你是怎么用这个的?

    无论如何,我认为您可能会遇到某种竞争条件,即客户端函数在服务器尝试调用它时可能并不总是可用。


    (附加 cmets/代码 2013-09-06)

    您的连接对象实际上是一个 jQuery 承诺 (http://api.jquery.com/category/deferred-object/)。

    如果您不熟悉 Promise,请将它们一般地视为稍后执行的回调队列。在这种情况下,当连接时,所有的回调都将被执行(按照它们被添加的顺序)。如果在连接后添加回调,它将立即执行。这就是您的代码现在的工作方式。建立连接后将回调添加到 .done 队列并立即执行。

    如果您坚持自己创建连接对象,则不需要使用 stateChanged 事件。您只需将回调添加到 .done 队列:

    define(function()
    {
        function signalRReady(callback)
        {
            if (window.connection == undefined) {
                window.connection = $.connection.hub.start();
            }
    
            window.connection.done(callback);
        }
    
        signalRReady.version = "1.0.0";
        return signalRReady;
    });
    

    但是,我认为自己发起连接并不是一个好主意。由于您的模块不是 SignalR 的完整包装器,因此人们只会使用您的模块来执行 SignalR 的工作,因此不能保证(并且不能期望)其他代码不会启动连接。特别是如果有人将您的模块添加到现有代码库中。

    您的模块只是添加一个新事件,因此请保持简单。获取回调并在适当的时候自行执行:

    define(function()
    {
        function signalRReady(callback)
        {
            $.connection.hub.stateChanged(function (state)
            {
                if(state.newState === $.signalR.connectionState.connected)
                {
                    callback();
                }
            });
        }
    
        signalRReady.version = "1.0.0";
        return signalRReady;
    });
    

    如今,promise 非常流行。你可能想要实现一个基于 Promise 的模块,例如:

    define(function()
    {
        var deferred = $.Deferred();
    
        $.connection.hub.stateChanged(function (state)
        {
            if(state.newState === $.signalR.connectionState.connected)
            {
                // executes all callbacks attached by the "ready" function below
                deferred.resolve();
            }
        });
    
        return {
            ready: function(callback)
            {
                deferred.done(callback);
            },
    
            version: "1.0.0"
        };
    });
    

    如果在建立连接后附加回调,它们会立即执行。

    另外,请注意这个示例模块的 init 函数返回一个对象而不是一个函数。由于 RequireJS 会将相同的实例传递给任何需要它的模块,因此状态保持不变——我们可以使用局部变量而不是全局变量。

    【讨论】:

    • 原来是这样,我发帖时才发现自己打错了。
    • 好吧,你链接的代码有一些逻辑问题。而且,没有任何东西可以显示你是如何使用模块的。似乎您在说您的问题是,当您第一次访问该页面时它可以工作,但是当您刷新该页面时却没有。但是您并没有显示正在运行的所有内容。我将通过对您现在在 github 中的代码的一些观察来更新我的“答案”,看看是否有什么能激发一个想法。
    • 我做了一些改变(基本上试图不改造 domReady 插件)并回到基础。正如您对此发表的评论一样,我有兴趣阅读您对此的看法。
    • 好多了 - 更简洁、更容易理解、更容易理解。但是,我认为您应该尝试不同的方法。作为一个仅在连接时检测并引发 **Ready 事件的模块,我认为它不应该是启动连接的模块。查看asp.net/signalr/overview/hubs-api/…(特别是 stateChanged 事件)。无需轮询 - 连接时会告知您。
    • 工作愉快 - stateChanged 减少了所需的代码量。我不得不使用 window.connection,因为当再次调用此模块时,连接需要全局可用。再次感谢 - 你们的 cmets 真的帮助我实现了我想要的!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多