Internet explorer IE中缺少通过信号器的原型方法

Internet explorer IE中缺少通过信号器的原型方法,internet-explorer,prototype,signalr,Internet Explorer,Prototype,Signalr,我遇到了一个处理原型方法消失的问题(在本例中是Array.prototype方法),仅在IE中,并且仅当数组通过信号器时 我编写了一个小型/愚蠢但简单的概念验证web应用程序来演示这个问题(代码如下)。请注意,当您单击“更新所有客户机”然后单击“包含字母“r”的水果”时,“U”列表中的原型方法将丢失,从而导致异常。在这种情况下,阵列来自信号器。现在,当您单击“重置”并将数组重置为硬编码值时,“包含字母“r”的水果”按钮突然起作用-原型方法又回来了。记住,这个问题只发生在IE中 提示:当我第一次写

我遇到了一个处理原型方法消失的问题(在本例中是Array.prototype方法),仅在IE中,并且仅当数组通过信号器时

我编写了一个小型/愚蠢但简单的概念验证web应用程序来演示这个问题(代码如下)。请注意,当您单击“更新所有客户机”然后单击“包含字母“r”的水果”时,“U”列表中的原型方法将丢失,从而导致异常。在这种情况下,阵列来自信号器。现在,当您单击“重置”并将数组重置为硬编码值时,“包含字母“r”的水果”按钮突然起作用-原型方法又回来了。记住,这个问题只发生在IE中

提示:当我第一次写概念证明时,我无法重现这个问题。当数组通过SignalR发送时,IE仍然使用原型方法,但当加载页面时,我确实出现了另一个错误。我意外地包含了两次jQuery。当我取出多余的脚本来包含第二个jQuery时,它修复了这个错误(很明显),但是现在这个问题可以重现了。IE当时错过了我创建的数组原型方法,但只有当数组通过信号器时

myExtensions.js:

Array.prototype.where = function (del)
{
    var ret = new Array();
    for (var i = 0; i < this.length; i++)
    {
        if (del(this[i])) ret.push(this[i]);
    }
    return ret;
}

Array.prototype.select = function (del)
{
    var ret = new Array();
    for (var i = 0; i < this.length; i++)
    {
        ret.push(del(this[i]));
    }
    return ret;
}
Index.cshtml

@{
    ViewBag.Title = "Home Page";
}

@if(false)
{
    @Scripts.Render("~/Scripts/jquery.signalR-1.0.0-rc1.js")
    @Scripts.Render("~/Scripts/myExtensions.js")
    <script src="~/signalr/hubs"></script>
}

<script type="text/javascript">

    var _fruits = ["blueberry", "grape", "orange", "strawberry"].select(function (f) { return { "Name": f } });
    var _list;

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

    conn.client.updateList = function (data)
    {
        _list = data;
        $("#theList").html("");
        for (var i = 0; i < _list.length; i++)
        {
            $("#theList").append("<li>" + _list[i].Name + "</li>");
        }
    }

    $(document).ready(function ()
    {
        $("#cmdUpdateClients").click(function ()
        {
            conn.server.runTest();
        });
        $("#cmdReset").click(function ()
        {
            conn.client.updateList(_fruits);
        });
        $("#cmdRunTest").click(function ()
        {
            var message = "";
            var fruitsContaining = _list
                .where(function (f) { return f.Name.indexOf('r') >= 0 })
                .select(function (f) { return f.Name });
            for (var i = 0; i < fruitsContaining.length; i++)
            {
                message += " - " + fruitsContaining[i] + "\n";
            }
            alert(message);
        });
        conn.client.updateList(_fruits);
    });


</script>

<input type="button" id="cmdUpdateClients" value="Update All Clients" />
<input type="button" id="cmdReset" value="Reset" />
<input type="button" id="cmdRunTest" value="Fruits containing the letter r." />
<ul id="theList"></ul>
@{
ViewBag.Title=“主页”;
}
@if(false)
{
@Scripts.Render(“~/Scripts/jquery.signalR-1.0.0-rc1.js”)
@Scripts.Render(“~/Scripts/myExtensions.js”)
}
var_fruits=[“蓝莓”、“葡萄”、“橙子”、“草莓”]。选择(函数(f){return{“Name”:f});
var_表;
var conn=$.connection.listHub;
$.connection.hub.start();
conn.client.updateList=函数(数据)
{
_列表=数据;
$(“#列表”).html(“”);
对于(变量i=0;i<\u list.length;i++)
{
$(“#列表”)。追加(“
  • ”+_列表[i]。名称+”
  • ”; } } $(文档).ready(函数() { $(“#cmdUpdateClient”)。单击(函数() { conn.server.runTest(); }); $(“#cmdReset”)。单击(函数() { conn.client.updateList(_); }); $(“#cmdRunTest”)。单击(函数() { var message=“”; var FROUTSCONTAINING=\u列表 .where(函数(f){返回f.Name.indexOf('r')>=0}) .select(函数(f){返回f.Name}); 对于(变量i=0;i

    我不确定这是否是我在代码中做错的事情(即,我在错误的顺序中做的事情),或者这是IE bug还是信号器bug。例如,当我在conn.client.updateList JS方法的第一行上设置断点,并将调用堆栈一直跟踪到最顶端时,我发现即使在“data”对象中(在signar receive方法中)的数组也没有我的原型方法。

    经过以下修改后,它对我来说效果很好:

    var fruitsContaining = _list
        .where(function (f) { return f.indexOf('r') >= 0 })
        .select(function (f) { return f});
    
    where和select实际上在那里,而f.Name没有,因为数组成员是字符串

    更新:

    好的,忽略上面的内容。以下是修复方法:

    var list = list
    if (navigator.appName == 'Microsoft Internet Explorer') {
        list = Array.prototype.slice.call(_list);
    }
    var fruitsContaining = list
        .where(function (f) { return f.Name.indexOf('r') >= 0 })
        .select(function (f) { return f.Name });
    for (var i = 0; i < fruitsContaining.length; i++) {
        message += " - " + fruitsContaining[i] + "\n";
    }
    
    var list=list
    如果(navigator.appName==“Microsoft Internet Explorer”){
    list=Array.prototype.slice.call(_list);
    }
    var FROUTSCONTAINING=列表
    .where(函数(f){返回f.Name.indexOf('r')>=0})
    .select(函数(f){返回f.Name});
    对于(变量i=0;i
    我不完全理解这个问题,但我相信这可能是jquery中的一个bug。虽然问题有点不同,但我从这个问题中得出了答案:

    附加更新


    添加了IE检查。

    我遇到了同样的问题:当我使用Signal r将数组从C#传递到Angular应用程序时,我无法对接收到的对象使用
    Array.prototype
    中定义的方法。此外,这些对象实际上是“类似于数组”的,因为所描述的一些数组测试将失败。例如,
    arry instanceof Array
    将返回
    false
    ,但
    Array.isArray(arr)
    将返回
    true

    当web应用程序托管在IIS中而不支持WebSocket时,问题就开始了。在这种情况下,在Chrome和Firefox中使用serverSentEvents,在internetexplorer和Edge中使用ForeverFrame

    ,ForeverFrame导致数组反序列化错误。这是因为ForeverFrame使用不同的帧来维护信号器连接,而不同帧中的数组是使用不同的
    Array
    对象创建的

    这里有许多解决方案:

  • 如果可能的话。这可以从IIS 8和Windows Server 2012开始执行
  • 如果WebSocket不可用,请在
    $.connection.hub.start()
    参数中指定不应使用ForeverFrame,默认为IE和Edge上的LongPolling
  • 您可以向ForeverFrame提供自己的JSON解析器,并调用
    window.JSON

    $.connection.hub.json = {
        parse: function(text, reviver) {
            console.log("Parsing JSON");
            return window.JSON.parse(text, reviver);
        },
        stringify: function(value, replacer, space) {
            return window.JSON.stringify(value, replacer, space);
        }
    };
    
  • 而且,正如Pete在回答中所建议的,您可以对接收到的对象调用
    Array.prototype.slice
    ,将其转换为同一帧的
    Array
    。必须对从SignalR接收的任何阵列执行此操作,因此它不像其他两个选项那样具有可伸缩性


  • 你能试试吗;在您的conn.client.updateList()方法中?这个主意很聪明,但是原型方法仍然缺失。实际上.Name就在那里。查看_list的初始化-select方法在数组的每个元素上创建.Name。集线器中的服务器端也会发生同样的情况。每个元素都是一个对象,而不是一个字符串。这就是为什么它在除IE之外的所有浏览器上都能通过Signal工作的原因。甚至当我看着你的时候
    var list = list
    if (navigator.appName == 'Microsoft Internet Explorer') {
        list = Array.prototype.slice.call(_list);
    }
    var fruitsContaining = list
        .where(function (f) { return f.Name.indexOf('r') >= 0 })
        .select(function (f) { return f.Name });
    for (var i = 0; i < fruitsContaining.length; i++) {
        message += " - " + fruitsContaining[i] + "\n";
    }
    
    $.connection.hub.json = {
        parse: function(text, reviver) {
            console.log("Parsing JSON");
            return window.JSON.parse(text, reviver);
        },
        stringify: function(value, replacer, space) {
            return window.JSON.stringify(value, replacer, space);
        }
    };