Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
399 views
in Technique[技术] by (71.8m points)

javascript - large arrays in dependent observables - cascading

I am using Knockout JS, as business requirements dictate that most, if not all logic is processed in the browser due to low bandwidth users. It's working out awesome so far except for one issue.

I am using a number of multiselect dropdown lists that all contain cascading logic. I have, say 8 lists that process hierarchical data and alter selectable options in child lists.

This is all good until I get to the bottom 2 lists which could potentially contain 3000 items depending on parent list selections (especially when 'select all' is clicked).

the problem is, in IE, I'm getting long running script warning messages, which I need to get rid of. Here's some code:

viewModel.BottomLevelList= ko.dependentObservable(function () {
        if (this.ParentList().length === 0) { //nothing selected
            return [];
        }          
        var result = [];
        var i = self.longMasterList.length;
        var currentId = 0;
        while (i--) {
           //psuodo code:
           //this.ParentList().Contains(loop-item) then
               //put in return list based on some further logic
           //else continue
        }

        return result;


    }, viewModel);

I have tried using various setTimeout techniques from SO to break the large array up and return control momentarily to the browser, but with no success. The result is never returned and / or the observable seems to detach itself leaving an empty list in the UI.

If I need to use AJAX I will, but this is a very last resort and would prefer to keep it in the client.

So my question boils down to:

  • How can I stop long running script warnings as a result of processing large data sets (in the context of Knockout JS dependant observables and cascading lists)
  • Is there some idiomatic JavaScript technique I could / should be using in this scenario
  • Am I not seeing the wood for the trees here?!

Thanks muchly for any help

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I would first suggest that you optimize your dependentObservable. When you read any observable, Knockout registers a dependency to it in Dependency Manager. It contains pretty simple code like this:

function registerDependency(observable) {
    if (ko.utils.arrayIndexOf(dependencies, observable)) {
        dependencies.push(observable);
    }
}

I can see in your pseudo-code that you are accessing this.ParentList() in the while loop. It means registerDependency will be called 3000 times and the dependencies array will be scanned 3000 times, which is bad for IE (since it has no built-in Array.indexOf method).

So my number one suggestion would be: Read all observables before loops.

If it doesn't help, I suggest that you proceed with setTimeout(). It is a bit tricky. Please check out this example: http://jsfiddle.net/romanych/4KGAv/3/

I have defined asyncObservable. You should pass an array with all dependencies of your dependentObservable. When ko.toJS is called, all observables are unwrapped. Then we call the passed callback function with arguments enumerated in the dependencies array. This function will be evaluated async.

I have wrapped this code into ko.dependentObservable to re-evaluate loader callback on any change of passed elements passed in dependencies

UPDATE: My code was overcomplicated for this issue. throttle extender will do the trick. Please checkout this sample: http://jsfiddle.net/romanych/JNwhb/1/


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...