отображение knockout.js, вызывающее бесконечную рекурсию в IE9

У меня бесконечная рекурсия в IE по моему отображению knockout.js. Может ли кто-нибудь, более знакомый с KO, определить, что я делаю не так?

У меня есть следующее отображение knockout.js:


        var mapping = {
            create: function(options) {
                return new MyViewModel(options.data);
            },
            'ChildItems': {
                create: function(options) {
                    return new ChildVM(options.data);
                }
            }
        }

Когда я визуализирую страницу, прибл. 1 раз из 5 IE заканчивает со следующим бесконечным стеком рекурсии (вызывая "SCRIPT28: Out of stack space"). Стек вызовов IE:


    fromJS
    MyViewModel
    create
    Anonymous Function
    withProxyDependentObservable
    createCallback
    updateViewModel
    fromJS
    MyViewModel
    create
    Anonymous Function
    withProxyDependentObservable
    createCallback
    updateViewModel
        ...

Конструктор моей модели представления:

 function MyViewModel(data) {
            var self = this;
            this.$type = 'MyViewModel';

            [some observables]         
            ...

            ko.mapping.fromJS(data, mapping, this);
        }

Инициализация модели представления выполняется путем вызова конечной точки json:


            $.ajax({
                url: 'http://my.end/point',
                type: 'POST',
                data: JSON.stringify(payload),
                contentType: 'application/json; charset=utf-8',
                success: function(data) {
                    window.vm = ko.mapping.fromJS(data, mapping);
                    ko.applyBindings(window.vm)
                    }
            });




Ответы (1)


Вы должны разделить свой объект отображения на 2 объекта. Используйте первое для отображения модели представления, а второе для детей.

var mapping = {
            create: function(options) {
                return new MyViewModel(options.data);
            }
        }

var childrenMapping = {
                'ChildItems': {
                    create: function(options) {
                        return new ChildVM(options.data);
                    }
                }
}

Ваш запрос ajax останется прежним. Обновите функцию MyViewModel для использования childrenMapping:

 function MyViewModel(data) {
            var self = this;
            this.$type = 'MyViewModel';

            [some observables]         
            ...

            ko.mapping.fromJS(data, childrenMapping, this);
        }

Основная причина проблемы - рекурсивный вызов сопоставления. Когда вы вызываете ko.mapping.fromJS(data, mapping); нокаут, вызывается правило создания, в котором создается объект MyViewModel. В конструкторе MyViewModel вы вызываете ko.mapping.fromJS из-за использования одних и тех же параметров сопоставления, но нокаут вызывает то же правило создания, которое создает объект MyViewModel, где ko.mapping.fromJS вызывается с теми же параметрами.

person Artem Vyshniakov    schedule 17.08.2012
comment
Спасибо, это действительно решило проблему. Не могли бы вы объяснить, в чем именно заключалась реальная проблема, которая в первую очередь вызвала рекурсию в IE? - person Fdr; 20.08.2012
comment
Что меня действительно смущает, так это то, почему такое поведение происходит только с IE, и еще больше сбивает с толку то, что это происходит только в 30-40% случаев? - person Fdr; 21.08.2012
comment
Может браузеры как-то этому мешают. - person Artem Vyshniakov; 21.08.2012