1

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

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

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();在尝试再次启动之前是否需要检查状态?

啤酒时间:)

4

1 回答 1

1

我相信应该是

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

(不是connection.server)

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定义了调用构造函数的函数并使这看起来很奇怪。你怎么用这个?

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


(附加评论/代码 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;
});

如今,承诺非常流行。您可能希望实现一个基于承诺的模块,例如:

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 会将相同的实例传递给任何需要它的模块,因此状态得以维护——我们可以使用局部变量而不是全局变量。

于 2013-06-27T20:37:56.580 回答