JQuery / Javascript - Как ждать обновления DOM, прежде чем продолжить с функцией - PullRequest
24 голосов
/ 08 сентября 2011

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

Я вижу, что div никогда не обновляется с помощью «Processing ...».Если я устанавливаю точку останова сразу после этой команды, то текст 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>

Ответы [ 3 ]

18 голосов
/ 08 сентября 2011

установите его на обработку, затем выполните setTimeout, чтобы запретить выполнение задачи с интенсивным использованием процессора до тех пор, пока 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
}
3 голосов
/ 08 сентября 2011

У вас есть цикл, который работает в течение 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');   
        })
    });
});

Ваниль 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/

0 голосов
/ 21 января 2019

Мне пришлось дождаться, пока 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();
});
...