Angular 7 Странное поведение от наблюдаемой подписки

У меня есть код для обработки некоторых данных, которые поступают из наблюдаемого, этот наблюдаемый получается через аннотацию @Input, я подписываюсь на наблюдаемый внутри моего NgOnInit(), все работало нормально, но мне нужно было добавить код, чтобы уменьшить обработку время данных, которые представляют собой массив массивов, мои данные выглядят так:

[['id1', объект, объект], ['id2', объект, объект]]

Итак, чтобы сократить время обработки, я создал переменную, которая будет содержать предыдущее постобработанное значение Observable, и я сравниваю предыдущие данные с новыми данными и обновляю только те данные, которые изменились, мой код выглядит так:

 private dataSetHolder: Array<any> = [];

constructor() { }


ngOnInit() {
    this.dataSet$.subscribe(data => { //line 43
        console.log('inicio: ', this.dataSetHolder);
        data.forEach(array => {
            const dataNoId = Object.assign([], array);
            const id = array[0];
            dataNoId.shift();
            let pacote: Package = { eixo_x: [], eixo_y: [] };
            if (this.dataSetHolder.length === 0) {
                pacote = this.separaDados(dataNoId, id, pacote);
                this.loadData(pacote);
            } else {
                this.dataSetHolder.forEach(arrayHolder => {
                    if (id === arrayHolder[0]) {
                        if (array.length > arrayHolder.length) {
                            pacote = this.separaDados(dataNoId, id, pacote);
                            this.loadData(pacote);
                        }
                    }
                });
            }
        });
        this.dataSetHolder = data; //line 64
    });
}

При выполнении строки 64 текущее значение данных передается в this.dataSetHolder, когда наблюдаемое получает новое значение, снова выполняется строка 43, а при выполнении строки 43 значение this.dataSetHolder обновляется, что не должно случиться, он должен быть обновлен только в строке 64.

Кто-нибудь понимает, что там происходит?

вставить описание изображения

вставить описание изображения

вставить описание изображения

Обратите внимание, что от этого последнего изображения к следующему я не нажимал «Продолжить отладку», я все еще нахожусь в строке 44.

вставить описание изображения

Я также попытался изменить строку 64 на это

            this.dataSetHolder = Object.assign([], data);

Потому что я думал, что это может быть вызвано javascript, потому что, когда я делаю this.dataSetHolder = data; на самом деле он не передает объект, а только ссылку, но это все равно не работает.


person Rodrigo Azevedo    schedule 30.01.2020    source источник
comment
Я думаю, что вы правы, и это потому, что вы назначаете по ссылке. Когда вы делаете Object.assign([], data); он копирует первый уровень вашего массива, но второй уровень все еще копируется по ссылке. Вам нужно будет сделать глубокую копию, чтобы она работала полностью, в вашем случае это должно работать с этим: this.dataSetHolder = []; data.foreach(dataItem => this.dataSetHolder.push({... dataItem}));   -  person bmtheo    schedule 31.01.2020
comment
Будьте осторожны, если вам нужен глубокий клон, вы можете использовать let clone = JSON.parse(JSON.stringify(objectToBeCloned)); Object.assign не работает для глубокого клонирования. developer.mozilla.org/en-US/ документы/Интернет/JavaScript/Справочник/   -  person EM15    schedule 31.01.2020
comment
Пожалуйста, не добавляйте ответы в вопрос. Не стесняйтесь добавить свой ответ, нажав кнопку ответа на мой вопрос   -  person Liam    schedule 31.01.2020
comment
Извините, я новичок в stackoverflow, но нет, Лиам, это не отвечает на мой вопрос, хотя проблема была почти такой же, как ранее объяснял bmtheo, мои данные представляли собой массив массивов, а массив контейнеров копировался, но массивы внутри массива контейнеров не копировались, на них ссылались, поэтому мне пришлось очистить массив памяти и скопировать в него каждый отдельный подмассив. Проблема, описанная в этом посте, такая же, но только на одном уровне, использование Object.assign() тоже было моей первой идеей.   -  person Rodrigo Azevedo    schedule 31.01.2020


Ответы (1)


Мой окончательный код выглядит так:

    ngOnInit() {
    this.dataSet$.subscribe(data => {
        data.forEach(array => {
            const dataNoId = Object.assign([], array);
            const id = array[0];
            dataNoId.shift();
            let pacote: Package = { eixo_x: [], eixo_y: [] };
            if (this.dataSetHolder.length === 0) {
                pacote = this.separaDados(dataNoId, id, pacote);
                this.loadData(pacote);
            } else {
                this.dataSetHolder.forEach(arrayHolder => {
                    if (id === arrayHolder[0]) {
                        const length = Object.keys(arrayHolder).length;
                        if (array.length > length) {
                            pacote = this.separaDados(dataNoId, id, pacote);
                            this.loadData(pacote);
                        }
                    }
                });
            }
        });
        this.dataSetHolder = [];
        data.forEach(dataItem => this.dataSetHolder.push({... dataItem}));
    });
}

Благодаря комментарию bmtheo я решил проблему, как он объяснил, даже использования Object.assign() для копирования данных недостаточно, так как мои данные представляют собой массив массивов, когда я использовал Object.assign(), я скопировал первый уровень моего массива, но массивы второго уровня не копировались, на них ссылались, поэтому данные менялись каждый раз, когда было доступно новое значение.

Решение состоит в том, чтобы очистить мой массив и скопировать в него каждый подмассив. в дополнение к этому мне пришлось изменить способ получения длины arrayHolder, поскольку он больше не интерпретировался как массив, он рассматривался как объект, ведьма не влияет на остальную часть кода, поэтому Я добавил это const length = Object.keys(arrayHolder).length; в свой код.

person Rodrigo Azevedo    schedule 31.01.2020
comment
Отлично, не забудьте принять ваш ответ, это пометит это сообщение как решенное - person bmtheo; 03.02.2020