Skip to content

pass shallow copy of updates to deliverChangeRecords method#21

Open
chopstikk wants to merge 1 commit intojdarling:masterfrom
chopstikk:master
Open

pass shallow copy of updates to deliverChangeRecords method#21
chopstikk wants to merge 1 commit intojdarling:masterfrom
chopstikk:master

Conversation

@chopstikk
Copy link

This is a fix for the following use case:
If the callback passed to the Observer is itself changing some of the object's properties, further updates are added to the queue (queueUpdates method) from within the for loop in the deliverChangeRecords method. In the current version of the polyfill, deliverChangeRecords processes the _updates, which are changed in different places. This leads to errors in the use case described above. My solution is to pass in a shallow copy of the _updates array to ensure that during processing the _updates (in deliverChangeRecord) they are not changed.

@jdarling
Copy link
Owner

Can you post a simple example that this breaks with so I can create a test case from it. Also the PR you submitted utilizes bind, as that isn't supported in all targeted environments we can't use it. Will have to rework the code a bit.

Once you post the test case I'll check it against Chromium and see what the expected behavior should be and see if I can't get an update together for it.

@chopstikk
Copy link
Author

I tried to make a simple example. Depending on the order of the props, the result varies when using the polyfill. In Chrome it works as expected.

var calculation1 = {
    value: 0,
    factor: 100,
    sum: 0
};

var calculation2 = {
    value: 0,
    factor: 100,
    sum: 0
};

// the result depends on the order of the observers when using the polyfill
var props1 = ['a', 'b', 'c', 'value', 'd', 'sum', 'e', 'f']; // works: i. e. result as expected
var props2 = ['a', 'b', 'sum', 'c', 'd', 'value', 'e', 'f']; // doesn't work: i. e. result not as expected

// the observe callback of prop 'value' changes the 'sum'
var observe = function (prop, calculation, exampleName) {
    var observer = function (changes) {
        changes.forEach(function (change) {
            var model = change.object;
            if (change.name === prop) {
                model.sum = model.value * model.factor;
                if (prop === 'sum') {
                    console.log(exampleName + ': sum: ', model.sum);
                }
            }
        });
        console.log(exampleName + ': value: ', calculation.value);
    };
    Object.observe(calculation, observer);
};

props1.forEach(function (prop) {
    observe(prop, calculation1, 'example 1');
});

props2.forEach(function (prop) {
    observe(prop, calculation2, 'example 2');
});

// simulate user interaction with range input
var i = 0;
var inputRangeInteraction = setInterval(function () {
    calculation1.value = ++i;
    calculation2.value = ++i;
    if (i > 20) {
        clearInterval(inputRangeInteraction);
    }
}, 10);

My fix is only some kind of a quick fix to make the polyfill work. Chrome's behaviour in this use case is more precise as the log output shows.

@jdarling
Copy link
Owner

Excellent, I'll take a look and see what I can put together, will take me a few days at minimum as I'm buried in real work and home activities.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments