область видимости в модели Дюрандаля

В одной из моих моделей просмотра у меня есть функция Control, которая позже создает объекты для привязки к представлению:

(Код воспроизводит только мою модель просмотра, поэтому он может быть неполным или содержать некоторые ошибки. Если вам нужна дополнительная информация, спросите в комментарии ниже. Поскольку пример относится к структуре durandaljs, я не могу предоставить JsFiddle.)

function Control ( value ) {
    var self = this;
    self.param = value;
    self.param1 = ko.observable(value.text());
    self.param2 = ko.computed(function() {
        read: function(){
            return getString(self.param.text()).StringValue();
        },
        write: function(newValue){
            stringsArray.push(
                {StringID: ko.observable(-1), StringValue: ko.observable(newValue)});
            self.param.text(-1);
        },
        owner: self
    });
    self.param3 = ko.computed(function() {
        return self.param2() + ' something_else';
    });
    self.param1.subscribe(function( newValue ) {
        if ( newValue ) {
            self.param3(newValue + 'text');
        }
    });

}

var controls = ko.observableArray([
    new Control({id: 1, text: ko.observable(2)}),
    new Control({id: 2, text: ko.observable(4)}),
    new Control({id: 2, text: ko.observable(1)})
]);

var stringsArray = ko.observableArray([
    {StringID: ko.observable(1), StringValue: ko.observable('aaa')},
    {StringID: ko.observable(2), StringValue: ko.observable('bbb')}
    {StringID: ko.observable(3), StringValue: ko.observable('ccc')}
    {StringID: ko.observable(4), StringValue: ko.observable('ddd')}
    {StringID: ko.observable(5), StringValue: ko.observable('eee')}
    {StringID: ko.observable(6), StringValue: ko.observable('fff')}
]); // data retrieved from the database

var deactivate = function() {
    controls.removeAll();
    stringsArray.removeAll();
};

var vm = {
    deactivate: deactivate,
    controls: controls,
    stringsArray: stringsArray
};
return vm;

function getString ( stringID ) {
    for ( var i = 0; i < stringsArray().length; i++ ) {
        if ( stringsArray()[i].StringID() === stringID ) {
            return stringsArray()[i];
        }
    }
    return undefined;
}

Моя проблема в том, что объекты, созданные из функции, имеют глобальную область видимости, поэтому, когда я деактивирую модель просмотра, они все еще существуют в памяти.

Как мне переписать function Control(value), чтобы создаваемые им объекты имели область видимости. Они будут существовать только тогда, когда модель просмотра активна и отброшены, когда я удалю их из observableArray в методе deactivate?


person Razvan    schedule 15.10.2013    source источник
comment
проверьте, включили ли вы cacheViews: true. Виртуальная машина возвращает синглтон, поэтому с cacheViews: true представление никогда не будет удалено.   -  person RainerAtSpirit    schedule 15.10.2013
comment
Я пробовал добавить cacheViews: false, но поведение осталось прежним. Проблема заключается в определении области действия объекта, созданного в function Control(). Прямо сейчас область действия созданного объекта глобальна. Я не знаю, как мне переписать функцию, чтобы областью объектов была только модель просмотра.   -  person Razvan    schedule 15.10.2013
comment
Можете ли вы разветвить приведенный ниже пример и воспроизвести это поведение?   -  person RainerAtSpirit    schedule 15.10.2013
comment
Это очень странно. Я поставил console.log(this) только в начале функции Control, и она напечатала объект Control {}. Я также поместил его в конец функции, и он вернул глобальный объект Window {...}.   -  person Razvan    schedule 15.10.2013
comment
dfiddle.github.io/dFiddle-2.0/#extras/scope ( github.com/dFiddle/dFiddle- 2.0 / blob / gh-pages / app / extras / scope /) использует исходный код, приведенный выше, но я не вижу ничего, что зависает в global. Можете ли вы воспроизвести это?   -  person RainerAtSpirit    schedule 15.10.2013
comment
Я не могу. Вычисленный по-прежнему выдает мне ошибку, что он ничего не находит в массиве строк после того, как я повторно перехожу к vm.   -  person Razvan    schedule 15.10.2013
comment
переместите stringsArray перед controls. stringsArray не определено, когда вы вызываете new Control (), поэтому это не удается.   -  person RainerAtSpirit    schedule 15.10.2013
comment
Нет. StringsArray не является неопределенным. Когда я повторно перехожу к представлению, я создаю элемент управления с разными свойствами и получаю разные строки. Ошибка возникает не из-за созданных мной новых вычислений, а из-за того, что я создал в прошлый раз, когда был на странице. Есть ли шанс, что нокаут может не уничтожить вычисленные значения, поскольку он зависит от stringsArray, а массив строк все еще находится в памяти?   -  person Razvan    schedule 15.10.2013
comment
Я забыл сказать, что удалил stringsArray.removeAll(); из метода deactivate, чтобы иметь возможность уходить от виртуальной машины. В противном случае вычисленное значение выдавало ошибку при вызове метода deactivate.   -  person Razvan    schedule 15.10.2013
comment
Re: `найти что-нибудь в массиве строк после того, как я перейду на`, что ожидалось. В deactivate есть вызов stringsArray.removeAll(). Пожалуйста, вернитесь, когда у вас будет пример, который работает и показывает проблему, которую вы видите. На данный момент слишком много движущихся частей.   -  person RainerAtSpirit    schedule 15.10.2013
comment
Это казалось проблемой. Явно удаляя вычисленное в функции deactivate for(var i=0;i<controls.peek().lenght;i++) {controls.peek()[i].param3.dispose(); controls.peek()[i].param3.dispose();}, у меня больше нет проблемы. Спасибо большое за вашу помощь!   -  person Razvan    schedule 15.10.2013
comment
Превосходно. Не могли бы вы добавить ответ и отметить его как принятый через пару дней. Таким образом, вопрос можно закрыть. Спасибо.   -  person RainerAtSpirit    schedule 16.10.2013


Ответы (2)


Интересный пример, но я не уверен, действительно ли приведенный выше код отражает то, что вы делаете, или это проблема копирования / вставки.

Я поднял dFiddle по адресу http://dfiddle.github.io/dFiddle-2.0/#extras/scope для его отладки. Не стесняйтесь форкнуть и модифицировать.

В настоящее время, когда вы уходите от представления, запускается событие живого цикла Дюрандаля deactivate, которое будет removeAll записи из stringArray и controls, но, конечно, оставит нокаут observableArrays в памяти, по крайней мере, если модель представления возвращает синглтон, а для cacheViews установлено значение true.

Скорее всего, я бы преобразовал vm в функцию-конструктор и, пока он работал, переместил элемент управления в свой собственный модуль, но, конечно, не зная точных требований, это просто внутреннее чувство.

Что-то вроде следующего должно помочь вам начать:

просмотреть модель

define(['durandal/system', 'jquery', 'knockout', './control'], function( system, $, ko, Control ) {
    "use strict";

    var vm = function() {
        this.controls = ko.observableArray([
            new Control('value1'),
            new Control('value2'),
            new Control('value2')
        ]);
    };

    vm.prototype.deactivate = function() {
        this.controls.removeAll();
    };

    return vm;
});

модуль контроля

define(['knockout'], function(  ko ) {
    "use strict";

    function Control ( value ) {
        this.param = value;
        this.param1 = ko.observable(value.text);
        this.param2 = ko.computed(function() {
            //translate self.param.StringID with data from another
            //an observableArray containing data retrieved from the server
            //return getString(this.param.StringID()).StringValue();
            return 'Computed' + this.param.id;
        // ko.computed takes a context parameter
        }, this);
        this.param3 = ko.computed(function() {
            return this.param2() + 'something_else';
        }, this);
        this.param1.subscribe(function( newValue ) {
            if ( newValue ) {
                this.param3(newValue + 'text');
            }
        });
    }

    var stringsArray = ko.observableArray([]); // data retrieved from the database

    return Control;

    function getString ( stringID ) {
        for ( var i = 0; i < stringsArray().length; i++ ) {
            if ( stringsArray()[i].StringID === stringID ) {
                return stringsArray()[i];
            }
        }
        return undefined;
    }

});

Живая версия доступна по адресу http://dfiddle.github.io/dFiddle-2.0/#extras/scope/ctor

person RainerAtSpirit    schedule 15.10.2013

По-видимому, моя проблема заключалась в том, что ko.computed содержался в объекте. Вычисленные данные не отбрасывались, когда я деактивировал модель просмотра, потому что некоторые внешние данные, от которых они зависели, все еще находились в памяти.

Я нашел об этом в этом сообщении: https://groups.google.com/d/msg/knockoutjs/4HV_PgcBNXA/ozoyXlygJHwJ

После удаления вручную ko.computed в функции деактивации проблема исчезла.

person Razvan    schedule 16.10.2013