Prototype methods missing in IE via SignalR
我遇到了一个问题,只在IE中处理原型方法消失(在本例中是array.prototype方法),而且只有当数组通过信号器时。
我写了一个小的/愚蠢的但简单的概念验证Web应用程序来演示这个问题(代码如下)。请注意,当您单击"更新所有客户机"然后单击"包含字母"r"的水果"时,"u"列表中的原型方法将丢失,从而导致异常。在这种情况下,阵列来自信号器。现在,当您单击"重置"并将数组重置为硬编码值时,"包含字母"r"的水果"按钮突然起作用——原型方法又回来了。记住,这个问题只发生在IE中。
提示:当我第一次写概念证明的时候,我不能复制这个问题。当数组通过信号器时,IE仍然有原型方法,但是当页面加载时,我确实有另一个错误。我无意中把jquery包括了两次。当我拿出多余的脚本来包含第二个jquery时,它修复了这个错误(显然),但现在问题可以重现了。然后,IE缺少了我创建的数组原型方法,但只有当数组通过信号器时。
myextensions.js(扩展名:myextensions.js)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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; } |
第四讲
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> @ViewBag.Title - My ASP.NET MVC Application <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" /> <meta name="viewport" content="width=device-width" /> @Styles.Render("~/Content/css") @Scripts.Render("~/Scripts/myExtensions.js") @Scripts.Render("~/bundles/modernizr") @Scripts.Render("~/Scripts/jquery-1.7.1.js") @Scripts.Render("~/Scripts/jquery.signalR-1.0.0-rc1.js") <script src="~/signalr/hubs"> </head> <body> <header> <p class="site-title">@Html.ActionLink("IE/SignalR error POC","Index","Home") </p> </header> @RenderSection("featured", required: false) <section class="content-wrapper main-content clear-fix"> @RenderBody() </section> <footer> <p> © @DateTime.Now.Year - My ASP.NET MVC Application </p> </footer> @*@Scripts.Render("~/Scripts/myExtensions.js")*@ </body> </html> |
速记
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | using System.Linq; using Microsoft.AspNet.SignalR.Hubs; namespace SignalR_Bug_POC.Hubs { public class ListHub : Hub { public void RunTest() { Clients.All.updateList(new string[] { "apple","pear","grape","strawberry","rasberry","orange","watermelon" }.Select(f => new { Name = f }).ToList()); } } } |
索引文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | @{ 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 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] +" "; } alert(message); }); conn.client.updateList(_fruits); }); <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> |
我不确定是我在代码中做错了什么(也就是说,我做错了顺序),还是IE错误或信号错误。例如,当我在conn.client.updateList JS方法的第一行设置一个断点,并将调用堆栈跟踪到最顶端时,会发现即使在"data"对象中(在signal-receive方法中),数组也没有我的原型方法。
我遇到了同样的问题:当我使用信号器将数组从C_传递到角度应用程序时,我不能在接收到的对象上使用
当Web应用程序宿主在不支持WebSockets的IIS中时,问题就开始了。在这种情况下,信号器在chrome和firefox中默认为serversentevents,在Internet Explorer和edge中默认为foreverframe。
正如这个问题所指出的,ForeverFrame导致数组反序列化错误。这是因为foreverframe使用不同的帧来保持信号器连接,不同帧中的数组是使用不同的
这里有很多解决方案:
您可以为foreverframe提供自己的JSON解析器,并调用
1 2 3 4 5 6 7 8 9 | $.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); } }; |
而且,正如皮特的回答中所建议的,你可以对接收到的对象调用
下面的修改对我来说很好:
1 2 3 | var fruitsContaining = _list .where(function (f) { return f.indexOf('r') >= 0 }) .select(function (f) { return f}); |
Where和Select实际上在那里,它是f.name,而不是,因为数组成员是字符串。
更新:
好吧,忽略上面的内容。这里是修复:
1 2 3 4 5 6 7 8 9 10 11 | 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] +" "; } |
我不完全理解这个问题,但我相信它可能是jquery中的一个bug。尽管这个问题有点不同,但我还是从这个问题中偷走了解决方案:为什么在我的jquery插件中,这个改变对数组原型不起作用?
其他更新
添加了IE检查。