Подтвердить что ты не робот

JQuery/Javascript - Как дождаться манипулирования DOM для обновления перед продолжением функции

То, что я пытаюсь сделать, - это обновить простой div, чтобы сказать "Обработка..." перед выполнением интенсивного процессора script (требуется 3-12 секунд для запуска, без AJAX), а затем обновить div сказать "Закончено!" когда сделано.

Я вижу, что div никогда не обновляется с помощью "Обработка..." . Если я установил точку останова сразу после этой команды, тогда текст div будет обновлен, поэтому я знаю, что синтаксис верен. Такое же поведение в IE9, FF6, Chrome13.

Даже при обходе jQuery и использовании основного исходного Javascript я вижу ту же проблему.

Вы бы подумали, что у этого будет легкий ответ. Однако, поскольку jQuery.html() и .text() не имеют крючка обратного вызова, это не опция. Он также не анимирован, поэтому манипулировать не нужно.

Вы можете проверить это сами, используя приведенный ниже пример кода, который показывает как реализацию jQuery, так и Javascript с 5-секундной высокопроцентной функцией. Код легко проследить. Когда вы нажимаете кнопку или ссылку, вы никогда не увидите "Обработка..."

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" ></script>
<script type="text/javascript">
function addSecs(d, s) {return new Date(d.valueOf()+s*1000);}
function doRun() {
    document.getElementById('msg').innerHTML = 'Processing JS...';
    start = new Date();
    end = addSecs(start,5);
    do {start = new Date();} while (end-start > 0);
    document.getElementById('msg').innerHTML = 'Finished JS';   
}
$(function() {
    $('button').click(function(){
        $('div').text('Processing JQ...');  
        start = new Date();
        end = addSecs(start,5);
        do {start = new Date();} while (end-start > 0);
        $('div').text('Finished JQ');   
    });
});
</script>
</head>
<body>
    <div id="msg">Not Started</div>
    <button>jQuery</button>
    <a href="#" onclick="doRun()">javascript</a>
</body>
</html>
4b9b3361

Ответ 1

установите его для обработки, а затем выполните команду setTimeout, чтобы предотвратить выполнение интенсивной задачи cpu до тех пор, пока не будет обновлен div.

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" ></script>
<script>
function addSecs(d, s) {return new Date(d.valueOf()+s*1000);}
function doRun() {
    document.getElementById('msg').innerHTML = 'Processing JS...';
    setTimeout(function(){
         start = new Date();
         end = addSecs(start,5);
         do {start = new Date();} while (end-start > 0);
         document.getElementById('msg').innerHTML = 'Finished Processing';   
    },10);
}
$(function() {
    $('button').click(doRun);
});    
</script>
    </head>
<body>
    <div id="msg">Not Started</div>
    <button>jQuery</button>
    <a href="#" onclick="doRun()">javascript</a>
</body>
</html>

вы можете изменить задержку setTimeout по мере необходимости, возможно, она будет больше для более медленных машин/браузеров.

Edit:

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

document.getElementById('msg').innerHTML = 'Processing JS...';
if ( confirm( "This task may take several seconds. Do you wish to continue?" ) ) {
     // run code here
}

Ответ 2

У вас есть цикл, который работает в течение 5 секунд и задерживает веб-браузер в течение этого времени. Поскольку веб-браузер заморожен, он не может сделать рендеринг. Вы должны использовать setTimeout() вместо цикла, но я предполагаю, что этот цикл является просто заменой для интенсивной работы процессора, которая занимает некоторое время? Вы можете использовать setTimeout, чтобы дать браузеру возможность выполнить рендеринг перед выполнением вашей функции:

JQuery

$(function() {
    $('button').click(function(){
        (function(cont){
            $('div').text('Processing JQ...');  
            start = new Date();
            end = addSecs(start,5);
            setTimeout(cont, 1);
        })(function(){
            do {start = new Date();} while (end-start > 0);
            $('div').text('Finished JQ');   
        })
    });
});

Vanilla JS:

document.getElementsByTagName('a')[0].onclick = function(){
    doRun(function(){
         do {start = new Date();} while (end-start > 0);
         document.getElementById('msg').innerHTML = 'Finished JS';   
    });
    return false;
};

function doRun(cont){
    document.getElementById('msg').innerHTML = 'Processing JS...';
    start = new Date();
    end = addSecs(start,5);
    setTimeout(cont, 1);
}

Вы также должны помнить, чтобы всегда объявлять все переменные с помощью ключевого слова var и не подвергать их воздействию глобальной области. Вот JSFiddle:

http://jsfiddle.net/Paulpro/ypQ6m/

Ответ 3

Мне пришлось ждать, пока jQuery будет манипулировать DOM, а затем захватить изменения (несколько раз загрузить поля формы в форму, а затем отправить ее). DOM вырос, и вставка заняла больше и больше времени. Я сохранил изменения, используя ajax, чтобы пользователь мог продолжить с того места, где он остановился.

Это НЕ РАБОТАЕТ, как предполагалось:

jQuery('.parentEl').prepend('<p>newContent</p>');
doSave(); // wrapping it into timeout was to short as well sometimes

Так как JQuery функции, такие как .prepend() делают продолжить цепь только тогда, когда сделано следующее, казалось, сделать трюк:

jQuery('.parentEl').prepend('<p>newContent</p>').queue(function() {
  doSave();
});

Ответ 4

С 2019 года используется двойной requesAnimationFrame для пропуска кадра вместо создания условия гонки с использованием setTimeout.

....
function doRun() {
    document.getElementById('msg').innerHTML = 'Processing JS...';
    requestAnimationFrame(() =>
    requestAnimationFrame(function(){
         start = new Date();
         end = addSecs(start,5);
         do {start = new Date();} while (end-start > 0);
         document.getElementById('msg').innerHTML = 'Finished Processing';   
    }))
}
...