mercredi 23 mai 2018

JavaScript '+=' operator causing race conditions when used with ES6 'await'; should it be changed from (x = x + y) to (x = y + x)?

I have been creating a service which recursively calculates the size of a folder on a filesystem. This involves summing the sizes of all files in the folder and then recursively summing the size of all subfolders using await and Promise.all. However I had a bug where the sizes of folders were not being summed but were overwriting each other, and after a lot of debugging I found it was caused by the behaviour of +=.

Consider the following example:

const waitAndReturn = async (x, timeout) => new Promise(resolve => setTimeout(resolve, timeout, x));

let plusEqualsSum = 0;
let alternativeSum = 0;

const plusEqualsIsWeird = async () => {
    const vals = [10, 5];
    await Promise.all(vals.map(async val => {
        plusEqualsSum += await waitAndReturn(val, 100);
        console.log(`plusEqualsSum += ${val}: ${plusEqualsSum}`)

        alternativeSum = await waitAndReturn(val, 100) + alternativeSum;
        console.log(`alternativeSum = ${val} + alternativeSum: ${alternativeSum}`)
    }));

    console.log(`Final plusEqualsSum: ${plusEqualsSum}`);
    console.log(`Final alternativeSum: ${alternativeSum}`);
};

plusEqualsIsWeird();

As we all know, x += y is equivalent to x = x + y; but when used with an async call, i.e. x += await y, the value of x at the time of the call is used rather than the value of x after the await. This causes a race condition when used in the above context, and seems unintuitive.

I am aware that x += y is equivalent to x = x + y, but argue that with the introduction of async/await it should be changed to x = y + x to avoid bugs like this. This would not change its behaviour when used in conjunction with synchronous values, but would be much clearer when used with async ones.

I am fairly new to JS so may either be doing something wrong or may have a poor philosophy on how x += y should behave, but the current behaviour seems really unintuitive to me.

What are your thoughts?




Aucun commentaire:

Enregistrer un commentaire