2017-07-09 30 views
0

場景:如何暫停observableArray的通知?

我正在創建一個基於knockout.js的長期運行的web應用程序,我需要爲我的viewmodels加載多次不同的數據。

爲了提高性能並避免不必要的更新,我需要在更新我的視圖模型期間臨時避免用於我的可觀察值和可觀察數組的正常依賴關係跟蹤鏈。 加載新數據完成後,我可以安全地恢復正常的ko依賴關係跟蹤。

要暫停observables我使用withPausing功能的偉大RP Niemeyer這裏描述:Change observable but don't notify subscribers in knockout.js

有沒有什麼辦法可以暫時忽略在可觀察陣列中的移除和插入?

回答

1

靈感來自實施pauseableComputed和可觀察withPausing我已經創建pauseableObservablepauseableObservableArray有需要時停止通知用戶,比恢復能力。它也對所有嵌套的可暫停屬性遞歸地工作。您可以玩HERE on Codepen

PauseableObservable:

// PauseableObservable - it's observable that have functions to 'pause' and 'resume' notifications to subscribers (pause/resume work recursive for all pauseable child). 

ko.isPauseableObservable = function(instance) { 
    return ko.isObservable(instance) && instance.hasOwnProperty("pause"); 
} 

ko.pauseableObservable = function(value) { 
    var that = ko.observable(value); 

    function getPauseableChildren() { 
     var currentValue = that(); 
     var properties = Object.getOwnPropertyNames(currentValue); 
     var pauseables = properties.filter((property) => { 
      return ko.isPauseableObservable(currentValue[property]); 
     }); 
     return pauseables.map((property) => { 
      return currentValue[property]; 
     }); 
    } 

    that.pauseNotifications = false; 
    that.isDirty = false; 

    that.notifySubscribers = function() { 
     if (!that.pauseNotifications) { 
      ko.subscribable.fn.notifySubscribers.apply(that, arguments); 
     } 
     that.isDirty = that.pauseNotifications; 
    }; 

    that.pause = function() {  
     that.pauseNotifications = true; 
     var pauseableChildren = getPauseableChildren(); 
     pauseableChildren.forEach((child) => { child.pause(); }); 
    } 

    that.resume = function() {  
     that.pauseNotifications = false; 

     if (that.isDirty) { 
      that.valueHasMutated(); 
     } 

     var pauseableChildren = getPauseableChildren(); 
     pauseableChildren.forEach((child)=> { child.resume(); }); 
    } 

    return that; 
} 

PauseableObservableArray

// PauseableObservableArray - it's observable array that have functions to 'pause' and 'resume' notifications to subscribers about add/remove items. 
// In case if array items pauseable observables - run recursively run 'pause'/'resume' on them. 

ko.pauseableObservableArray = function(items) { 
    var that = ko.observableArray(items); 

    that.pauseNotifications = false; 
    that.isDirty = false; 
    that.lastNotification = []; 

    that.notifySubscribers = function() { 
     if (!that.pauseNotifications) { 
      ko.subscribable.fn.notifySubscribers.apply(that, arguments); 
     } else { 
      that.lastNotification = arguments; 
     } 
     that.isDirty = that.pauseNotifications; 
    }; 

    that.pause = function() { 
     var items = that(); 
     that.pauseNotifications = true; 
     items.forEach(function(item) { 
      if(ko.isPauseableObservable(item)) { 
       item.pause(); 
      } 
     }); 
    } 

    that.resume = function() { 
     var items = that(); 
     that.pauseNotifications = false; 

     if(that.isDirty) { 
      ko.subscribable.fn.notifySubscribers.apply(that, that.lastArguments); 
     } 
     items.forEach(function(item) { 
      if(ko.isPauseableObservable(item)) { 
       item.resume(); 
      } 
     }); 
    } 

    that.refresh = function() { 
     that.resume(); 
     that.pause(); 
    } 

    return that; 
} 

用例:

var firstItem = ko.pauseableObservable("Hello"); 
var secondItem = ko.pauseableObservable("World"); 
var items = [ 
    firstItem, 
    secondItem 
]; 
var array = ko.pauseableObservable(items); 

// Stop notifications from specific observable 
firstItem.pause(); 
// Change won't raise notification to subscribers 
firstItem("Hi"); 
// Resume notifications 
firstItem.resume(); 

// Stop notifications from all items of array 
array.pause(); 
// Change won't raise notification to subscribers 
array.push("Hey"); 
array()[0]("Hi"); 
// Resume notifications 
array.resume();