Странная JS функция «нарезанного» потока выполнения - PullRequest
2 голосов
/ 10 января 2020

У меня действительно странное поведение при выполнении функции.

Вот контекст: я пишу некий инструмент для рисования, основанный на манипуляциях с холстом. Мне нужно взять данные с основного холста и применить к нему процесс каждые N секунд (заменив цвет другим, и установите значение 0,0,0,0 для каждого второго пикселя). Затем обработанные данные помещаются в saveCanvas.

Функция:

function replaceColorByAnotherColor(data, oldRgbColor, newRgbColor, opacity) {
    let i = 0;
    let testTime = new Date();
    let testPos = 0;
    let testNeg = 0;
    while (i < data.length) {
        if (
            data[i] >= oldRgbColor.r - 50 &&
            data[i] <= oldRgbColor.r + 50 &&
            data[i + 1] >= oldRgbColor.g - 50 &&
            data[i + 1] <= oldRgbColor.g + 50 &&
            data[i + 2] >= oldRgbColor.b - 50 &&
            data[i + 2] <= oldRgbColor.b + 50
        ) {
            testPos++;
            data[i] = newRgbColor.r;
            data[i + 1] = newRgbColor.g;
            data[i + 2] = newRgbColor.b;
            data[i + 3] = opacity;
        } else {
            testNeg++;
            data[i] = 0;
            data[i + 1] = 0;
            data[i + 2] = 0;
            data[i + 3] = 0;
        }
        i += 4;
    }
    console.log(data.length);
    console.log(testPos);
    console.log(testNeg);
    console.log(new Date() - testTime + ' ms');
}

Вот JsFiddle , которая пытается воспроизвести ситуацию.

Итак, вот проблема, с которой я сталкиваюсь: иногда выполнение моей функции процесса занимает очень много времени (от ~ 80 мс до более чем 7 секунд!).

Когда я использую инструмент "производительность" в Chrome отладчик, вот что я нашел:

Когда после выполнения я не обновляю sh объект, читая картинку с основного холста (что я должен сделать для всего своего кода, чтобы работает правильно), моя функция выполняется нормально, например this JsFiddle : normal execution

Но если после выполнения я переосмыслил sh объект с getImageData() на главном холсте выполнение моей функции - это своего рода фрагмент (и он намного длиннее), которого я никогда раньше не видел, как в this JsFiddle : sliced execution Zoomed: sliced execution zoom

Я также указал, что в любом случае 3 или 4 в первый раз tions работает как заклинание, до того, как ошибка (или что-то еще) происходит.

Я не имею понятия о том, что происходит с этим исполнением.

Есть ли у вас какие-либо идеи? или вы когда-нибудь сталкивались с таким поведением раньше?

Спасибо!

РЕДАКТИРОВАТЬ 1:

Мне удалось вести себя так же без Реагируйте стеком в этот JsFiddle . Кстати, извините за отвратительную строку base64 в начале скрипки. Это мой первый раз с JsFiddle, я не знаю, как включить другие файлы, и я думаю, что моя проблема связана с размером изображения.

Как предложил @Bonatti, я включил основную функцию выше. И вот основной код:

<div>
  <canvas style="width:200px" id="mainCanvas" width="3280" height="2464"></canvas>
  <canvas style="width:200px" id="saveCanvas" width="3280" height="2464"></canvas>
</div>
var test = {
    src:"data:image/png;base64,iVBOR....."
}

let imageData = null;
let mainTimeout = setTimeout(() => {processCanvas()},10000);

let mainCanvas = document.getElementById('mainCanvas');
let mainCtx = mainCanvas.getContext('2d');

let saveCanvas = document.getElementById('saveCanvas');
let saveCtx = saveCanvas.getContext('2d');

let image = new Image();
image.onload = () => {
    mainCtx.drawImage(image,0,0);
    imageData = mainCtx.getImageData(0,0,3280,2464);
}
image.src = test.src;

var refreshImageData = () => {
    imageData = mainCtx.getImageData(0,0,3280,2464);
}

var processCanvas = () => {
    console.log('====== PROCESS ======');
    clearTimeout(mainTimeout);
    refreshImageData();
    replaceColorByAnotherColor(imageData.data, {r:255,g:0,b:0}, { r: 0, g: 255, b: 0 }, 255);
    saveCtx.putImageData(imageData, 0, 0);
    refreshImageData();
    mainTimeout = setTimeout(() => {processCanvas()},10000);
}

Результат выполнения:

====== PROCESS ======
32327680
161417
7920503
63 ms
====== PROCESS ======
32327680
161417
7920503
225 ms
====== PROCESS ======
32327680
161417
7920503
2566 ms

И после этого он никогда не опускается ниже 2000 мс.

РЕДАКТИРОВАТЬ 2:

Похоже, проблема возникает, когда я читаю или пишу в массиве data.

Это происходит, если я делаю:

while (i < data.length) {
    if (data[i] === oldRgbColor.r) {
        testPos++;
    } else {
        testNeg++;
    }
    i += 4;
}

Но нет, если я сделаю

while (i < data.length) {
    if (i % 5) {
        testPos++;
    } else {
        testNeg++;
    }
    i += 4;
}

1 Ответ

0 голосов
/ 13 января 2020

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

Я просто поместил .r .g и .g в разделители переменных и сделал

while (i < data.length) {
    if (
        data[i] >= oldR - 50 &&
        data[i] <= oldR + 50 &&
        data[i + 1] >= oldG - 50 &&
        data[i + 1] <= oldG + 50 &&
        data[i + 2] >= oldB - 50 &&
        data[i + 2] <= oldB + 50
    ) {
        test1++;
        data[i] = newR;
        data[i + 1] = newG;
        data[i + 2] = newB;
        data[i + 3] = opacity;
    } else {
        test2++;
        data[i] = 0;
        data[i + 1] = 0;
        data[i + 2] = 0;
        data[i + 3] = 0;
    }
    i += 4;
}

и теперь он работает как шарм!

Я не могу объяснить почему, я не понимаю, почему он так себя ведет.

Я отмечаю свой ответ как решено, но если кто-то столкнется с этим и поймет, что случилось, не стесняйтесь объяснить это!

...