Javascript - проблема закрытия setTimeout - PullRequest
7 голосов
/ 28 февраля 2012

Я борюсь с кодом ниже. Я пробовал много разных способов сделать это, но в результате я получил один из двух неверных результатов.

for(i = 0; i < result.length; i++) {

    var tmpBlockInfo = {
        size: worldTest.data[0].size,
        xStartPixel :  result[i].x * worldTest.data[0].size,
        yStartPixel : result[i].y * worldTest.data[0].size,
        blockType : (Math.random() * 100 > 10) ? 'path' : 'wall'
    }

    var tmpFunc = function(){
        worldTest.fillBlock(tmpBlockInfo, 157, 152, 124,  255)
    };

    var t = setTimeout(function(){
        tmpFunc()
    } , 500 * i);
}

Проблема с приведенным выше кодом заключается в том, что tmpBlockInfo всегда получает последний результат [i] .x / result [i] .y. Поэтому я полагаю, что когда тайм-аут запускает функцию, она видит, какой результат [i] .x / result [i] .y был оставлен включенным после цикла (вместо того, чтобы передавать его как «новую» переменную)

Я думал, что включение в функцию решит проблему закрытия, но не повезло.

Также пробовал:

for(i = 0; i < result.length; i++) {

    var tmpBlockInfo = {
        size: worldTest.data[0].size,
        xStartPixel :  result[i].x * worldTest.data[0].size,
        yStartPixel : result[i].y * worldTest.data[0].size,
        blockType : (Math.random() * 100 > 10) ? 'path' : 'wall'
    }

    var t = setTimeout(function(){
        worldTest.fillBlock(tmpBlockInfo, 157, 152, 124,  255)
    } , 10000 * i);
}

С теми же результатами, что и первый код.

Если я это сделаю:

for(i=0; i < result.length; i++) {

    var tmpBlockInfo = {
        size: worldTest.data[0].size,
        xStartPixel :  result[i].x * worldTest.data[0].size,
        yStartPixel : result[i].y * worldTest.data[0].size,
        blockType : (Math.random() * 100 > 10) ? 'path' : 'wall'
    }

    setTimeout(function(passBlockInfo) {
        worldTest.fillBlock(tmpBlockInfo, 157, 152, 124,  255) 
    } (tmpBlockInfo), 1000 * i);
}

Он правильно обрабатывает все функции fillBlock. НО он делает их все одновременно (например, он не запускает их по одному за раз. Он просто делает их друг за другом, но вызывает блокировку (без обновления экрана) и никакой задержки между ними.

Любая помощь с этим была бы великолепна!

Ответы [ 4 ]

7 голосов
/ 28 февраля 2012

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

function MakeTimeoutCall(fn, data, timeout){
    setTimeout(function() {fn.call(null, data);}, timeout);
}

Затем в вашем цикле, где вы вызываете setTimeout, сделайте это

MakeTimeoutCall(
    function(passBlockInfo){
       worldTest.fillBlock(passBlockInfo, 157, 152, 124,  255);
    },
    tmpBlockInfo,
    1000 * i);

(Предполагается, что worldTest является глобальным объектом).

Это должно сработать. setTimeout ожидает, что функция будет вызвана в конце тайм-аута, вы даете свою функцию, но вызываете ее сразу. Возвращаемое значение, в данном случае нулевое, затем передается тайм-ауту. Так что тайм-аута нет, все происходит сразу.

На всякий случай, если мой ответ немного сложен, учитывая контекст, здесь - это ссылка на более простое решение в jsfiddle.

4 голосов
/ 28 февраля 2012

Попробуйте это:

for(i = 0; i < result.length; i++) {
    var tmpBlockInfo = {
        size: worldTest.data[0].size,
        xStartPixel :  result[i].x * worldTest.data[0].size,
        yStartPixel : result[i].y * worldTest.data[0].size,
        blockType : (Math.random() * 100 > 10) ? 'path' : 'wall'
    }
    var t = setTimeout(createFillBlockFn(tmpBlockInfo) , 500 * i);
}

function createFillBlockFn(blockInfo) {
    return function() {
        worldTest.fillBlock(blockInfo, 157, 152, 124,  255)
    }
}
0 голосов
/ 28 февраля 2012

Этот код поможет вам:

for(i=0; i < result.length; i++)
{
    setTimeout(function(){
        {
            size: worldTest.data[0].size,
            xStartPixel :  result[i].x * worldTest.data[0].size,
            yStartPixel : result[i].y * worldTest.data[0].size,
            blockType : (Math.random() * 100 > 10) ? 'path' : 'wall'
        }, 157, 152, 124,  255);
    } , 500 * i);
}

Переменные объявлены в верхней части функции, поэтому у вас есть один var tmpBlockInfo, ont tmpFunc и те переменные, которые вы переназначаете.

0 голосов
/ 28 февраля 2012

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

for(i=0; i < result.length; i++) {

    setTimeout(function () {

        var tmpBlockInfo = {
            size: worldTest.data[0].size,
            xStartPixel :  result[i].x * worldTest.data[0].size,
            yStartPixel : result[i].y * worldTest.data[0].size,
            blockType : (Math.random() * 100 > 10) ? 'path' : 'wall'
        };

       return function () {
           worldTest.fillBlock(tmpBlockInfo, 157, 152, 124,  255);
       };
    }(), 1000 * i);
}
...