Knockout.js中sorted与rateLimit联用触发无限循环问题
Knockout.js中sorted与rateLimit扩展结合导致无限循环的问题解决
在Knockout.js中同时使用自定义的sorted扩展和官方的rateLimit扩展时,出现了无限循环的异常。单独使用任意一个扩展都正常,但两者结合后循环无法停止。
原因分析
- 自定义
sorted扩展的逻辑缺陷:扩展内部通过ko.computed监听数组变化,每次触发就调用obs.sort()修改原数组。而sort方法会触发observableArray的arrayChange通知,这又会重新触发ko.computed执行,形成潜在的循环触发条件。 rateLimit的延迟通知机制加剧循环:当启用rateLimit的notifyWhenChangesStop模式时,数组的变更通知会被延迟处理。此时sorted扩展执行sort修改数组,rateLimit会将这次变更纳入待通知队列;队列处理时又会触发computed再次执行sort,由于延迟机制的存在,每次sort都被视为新的有效变化,最终导致无限循环。- 单独使用
sorted无循环的原因:单独使用时,sort执行一次后数组已处于有序状态,再次执行sort不会改变数组内容,因此不会触发新的arrayChange通知,computed自然停止执行。但rateLimit打破了这个终止条件,让每次sort都被当作需要通知的变更。
解决方案
方案1:修改sorted扩展,避免重复排序
优化扩展逻辑,仅当数组未处于有序状态时才执行排序,减少不必要的数组修改:
ko.extenders.sorted = function (obs, sortFunction) { ko.computed(function () { var currentArray = obs(); // 检查数组是否已排序 var isSorted = true; for (var i = 0; i < currentArray.length - 1; i++) { if (sortFunction(currentArray[i], currentArray[i+1]) > 0) { isSorted = false; break; } } if (!isSorted) { console.log('sorting'); obs.sort(sortFunction); } }); };
方案2:改用computed返回排序后的数组(推荐)
避免直接修改原observableArray,通过computed派生排序后的数组,从根源上消除修改原数组引发的循环:
function Unscheduled() { var self = this; // 原数组仅添加rateLimit扩展 self.rawGames = ko.observableArray([]).extend({ rateLimit: { timeout: 0, method: "notifyWhenChangesStop" } }); // 用computed返回排序后的数组 self.games = ko.computed(function() { return self.rawGames().sort(function(l, r) { return l.length > r.length ? -1 : 1; }); }); self.changes = ko.observable(0); self.rawGames.subscribe(function (changes) { console.log('Array Hit'); self.changes(self.changes()+1); }, null, "arrayChange"); self.rawGames.push('test'); self.addRemove = function() { self.rawGames.remove('test1'); self.rawGames.push('test'); } } ko.applyBindings(new Unscheduled());
对应的HTML调整(如需展示排序后的数组):
<script src="https://exposureevents.com/scripts/knockout-3.5.0.min.js"></script> <div data-bind="text: changes"></div> <button data-bind="click: addRemove">Add/Remove</button> <ul data-bind="foreach: games"> <li data-bind="text: $data"></li> </ul>
内容的提问来源于stack exchange,提问作者Mike Flynn
相关产品推荐
相关产品推荐

