Underscorejs 'defer' (или setTimeout 1) не работает последовательно

В крупномасштабном приложении JavaScript у меня есть похожий случай:

var $box = $('#box');
var expensiveOperation = function () {
    for (var i = 0; i < 10000; i++) {
        for (var j = 0; j < 4500; j++) {
            Math.random();
        }
    }
};

$('#show').click(function () {
    $box.show();
    expensiveOperation();
});

$('#showDefer').click(function () {
    $box.show();
    _.defer(expensiveOperation);
});

$('#hide').click(function () {
    $box.hide();
    expensiveOperation();
});
$('#hideDefer').click(function () {
    $box.hide();
    _.defer(expensiveOperation);
});
#box {
    background-color:red;
    width:100px;
    height:100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="box"></div>
<button id="show">show</button>
<button id="showDefer">show defer</button>
<button id="hide">hide</button>
<button id="hideDefer">hide defer</button>

Ссылка на jsFiddle, на всякий случай: http://jsfiddle.net/oymaterz/5/

Я хочу скрыть или показать элемент DOM и выполнить дорогостоящую операцию. Из соображений производительности я хочу всегда обеспечивать, чтобы показ / скрытие выполнялись первыми (то есть в верхней части стека выполнения). Это продемонстрировано в приведенном мною примере (с использованием отложенного подчеркивания) и его работоспособности в последней версии Chrome. Кроме того, приведенный выше пример не работает на IE11. Спрятать / показать отложенное все еще медленно.

Тем не менее, когда я делаю то же самое в моем приложении, оно работает только периодически, и странно, что IE11, кажется, постоянно работает нормально.

Есть идеи, почему я так поступаю?

1 ответ

Решение

Я нашел решение своей проблемы. Хотя ожидается, что _.defer (из setTimeout 1) должен был сработать... в моем случае это было не совсем согласованно. В итоге я использовал метод requestAnimationFrame. Вот обновленная версия:

var expensiveOperation = function () {
    for (var i = 0; i < 10000; i++) {
        for (var j = 0; j < 4500; j++) {
            Math.random();
        }
    }
};


var $box1 = $('#box-1');


$('#show-1').click(function () {
    $box1.show();
    expensiveOperation();
});

$('#showDefer').click(function () {
    $box1.show();
    _.defer(expensiveOperation);
});

$('#hide-1').click(function () {
    $box1.hide();
    expensiveOperation();
});

$('#hideDefer').click(function () {
    $box1.hide();
    _.defer(expensiveOperation);
});

var $box2 = $('#box-2');

$('#show-2').click(function () {
    $box2.show();
    expensiveOperation();
});

$('#showRequestAnimationFrame').click(function () {
    var flag = true;
    requestAnimationFrame(function showAnimFrame(){
        if(flag) {
            $box2.show();
            flag = false;
            requestAnimationFrame(showAnimFrame);
        } else expensiveOperation();
    });
});

$('#hide-2').click(function () {
    $box2.hide();
    expensiveOperation();
});

$('#hideRequestAnimationFrame').click(function () {
     var flag = true;
    requestAnimationFrame(function showAnimFrame(){
        if(flag) {
            $box2.hide();
            flag = false;
            requestAnimationFrame(showAnimFrame);
        } else expensiveOperation();
    });
});
#box-1 {
    background-color:red;
    width:100px;
    height:100px;
}

#box-2 {
    background-color:blue;
    width:100px;
    height:100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="box-1"></div>
<button id="show-1">show</button>
<button id="showDefer">show defer</button>
<button id="hide-1">hide</button>
<button id="hideDefer">hide defer</button>

<p></p>

<div id="box-2"></div>
<button id="show-2">show</button>
<button id="showRequestAnimationFrame">show requestAnimationFrame</button>
<button id="hide-2">hide</button>
<button id="hideRequestAnimationFrame">hide requestAnimationFrame</button>

Ссылка на jsFiddle, на всякий случай: http://jsfiddle.net/oymaterz/6/

Стоит отметить, что requestAnimationFrame не поддерживается в IE8. Если вам нужна поддержка, я предлагаю использовать превосходный GIST Пола Айриша для кросс-браузерной совместимости.

Я надеюсь, что это поможет кому-то в такой же ситуации, как и я. Теперь он отлично работает для меня и доказал, что спасает жизнь.

Другие вопросы по тегам