Sleep() в Javascript
Предположим, я хочу заблокировать выполнение Javascript на некоторое время по какой-то странной причине, как я могу это сделать. В JS нет сна(). Pls не говорит делать while() цикл, потому что это плохо. Я могу сделать window.showModalDialog и поместить window.close в модальный диалог с setTimeout очень малого времени, чтобы пользователь не заметил диалог. Это будет похоже на сон в течение небольшого периода времени, и я могу назвать это несколько раз, если это необходимо. Есть ли другой способ?
Чтобы разработать, мой вариант использования заключается в том, что HTML5 SQL Database предоставила async api, но я хочу использовать его для web-сервера samll, для которого магазин никогда не будет большим. Таким образом, нет необходимости в async api, потому что запросы в небольшом магазине будут выполняться на стороне клиента. Поэтому я хочу написать ORM с sync api, чтобы разработчики могли использовать его более легко. Чтобы свести эту асинхронную синхронизацию к api, мне нужно что-то вроде сна.
Ответы
Ответ 1
window.setTimeout
или window.setInterval
в значительной степени ваши единственные друзья.
Пример использования setTimeout
для рекурсивного вызова функции, задающей другой тайм-аут, выглядит следующим образом
function go() {
if (go.count < 4) {
// logs 1, 2, 3 to firebug console at 1 second intervals
console.log(go.count++);
window.setTimeout(go, 1000);
}
}
go.count = 1;
go();
Вы можете выбрать захват тайм-аута для использования с window.clearTimeout
, если вам нужно очистить таймаут до его окончания.
Обратите внимание, что ни window.setTimeout
, ни window.setInterval
блокировать выполнение других script - я не верю, что это возможно с JavaScript в этом текущем обличье. Существуют способы, которые могут быть закодированы для имитации блокировки пользовательского интерфейса, например, с использованием showModalDialog
или с некоторым глобальным blocking
логическим значением, которое примерно так же близко, как вы можете получить, я боюсь.
Ответ 2
@Russ Cam верен, setTimeout
- это то, что вы ищете. Однако, как вы упоминали об этом в вопросе, мне кажется, что может быть некоторая путаница в том, как он используется.
Он не будет блокировать выполнение блока, в котором он находится, скорее, он будет вызывать свою функцию ввода через определенный интервал. В качестве иллюстрации:
function illustration() {
// start out doing some setup code
alert("This part will run first");
// set up some code to be executed later, in 5 seconds (5000 milliseconds):
setTimeout(function () {
alert("This code will run last, after a 5 second delay")
}, 5000);
// This code will run after the timeout is set, but before its supplied function runs:
alert("This will be the second of 3 alert messages to display");
}
При запуске этой функции вы увидите три предупреждающих сообщения с задержкой между вторым и третьим:
- "Эта часть будет работать первой"
- "Это будет второе из 3 предупреждающих сообщений для отображения"
- "Этот код будет работать последним, после 5-секундной задержки"
Ответ 3
Чтобы уточнить: вопрос заключается в том, чтобы полностью приостановить выполнение script в течение определенного времени, а не задерживать выполнение какого-либо фрагмента кода, который будет задачей для setTimeout или setInterval.
Чистая реализация sleep() просто невозможна, а также нежелательна в JavaScript.
setTimout и setInterval НЕ останавливают выполнение script, как некоторые люди здесь выглядят сверху. Просто зарегистрируйте функцию, которую нужно запустить отложить. Остальная часть script будет продолжать работать, пока ожидает время ожидания/интервал.
Из-за асинхронного характера JavaScript единственный способ "заблокировать" выполнение любого кода был бы очень уродливым и абсолютно НЕ РЕКОМЕНДУЕМ, пока цикл, который выполняется в течение определенного времени.
Поскольку сам JavaScript работает в одном потоке (мы здесь не говорим об API WebWorkers...). Это остановит выполнение любого JS-кода до тех пор, пока этот цикл не завершится. Но это действительно плохой стиль...
Если ваша программа не может работать без чего-то вроде sleep(), возможно, вам следует пересмотреть свой подход.
Ответ 4
Этот ответ может быть немного раздражающим, но голым с ним:-).
Так как javascript обычно запускается внутри браузера, который многопоточен, из которого javascript может занимать несколько потоков, нет понятия "глобального сна", как вы могли бы иметь в однопоточной программе.
Если вы хотите приостановить операцию любым разумным способом, вы можете рассмотреть следующее.
Скажем, вы хотите следующее
function foo(s) {
var j = 1; var k = 1;
sleep(s); // This would be nice right?
window.alert("Sum is : " + (j+k));
}
На самом деле становится:
function foo(s) {
var j = 1 ; var k = 1;
setTimeout(s, function() {
window.alert("Sum is : " + (j+k));
});
}
Конечно, проблема заключается в том, что в процедурном смысле вы можете иметь что-то вроде
function foo() {
do stuff;
pause();
do more stuff;
return;
}
function bar() {
foo(10);
window.alert("I want this to happen only after foo()");
}
Проблема в том, что вы не можете сделать это с помощью setTimeout, как показано выше
Однако вы можете сделать что-то вроде:
function foo(s, afterwards, afterparms) {
var j = 1 ; var k = 1;
setTimeout(s, function() {
window.alert("Sum is : " + (j+k));
afterparms.parm1 = afterparms.parm1.toUpperCase();
afterwards(afterparms);
});
}
function bar() {
foo(10, function() {
window.alert("This will happen after window.alert");
}, { parm1: 'hello', parm2: 'world' } );
}
Обратите внимание, что выше - это только ОДИН способ передачи информации в функции, вы можете сделать некоторые действительно классные вещи, если вы посмотрите на вызовы функций, переменные аргументы и такие
Это раздражает программирование, если вы считаете это процедурным. Однако в javascript есть две вещи, которые нужно запомнить. Это НЕ процедурный язык, NOR - объектно-ориентированный язык. Javascript - это функциональный язык со сложной моделью управления событиями. Поэтому вы должны думать в этих терминах.
Это тоже имеет смысл, поскольку типичная машина javascript - это gui (веб-браузер), который по дизайну не хочет полностью блокировать, пытаясь что-то обработать. Представьте, что ваш браузер полностью блокируется, пока страница что-то делает, вы хотите задушить программиста, который сделает это с вами.
Javascript-код должен быть "огненным и забытым", и если вам нужно дождаться события, прежде чем продолжить, вы должны посмотреть на модель событий javascript.
Хотя это неудобное программирование, когда вы хотите сделать что-то тривиальное, скорее всего, вы используете паузу, чтобы подождать таким образом, чтобы начать с условий гонки, и что есть более подходящий способ сделать "эффект", который вы пытаетесь достичь.
Если вы опубликуете свой ОПРЕДЕЛЕННЫЙ случай, может появиться больше информации о том, как можно решить такую ситуацию.
Приветствия,
Ответ 5
Я могу сделать window.showModalDialog и поместить window.close в модальный диалог с setTimeout очень малого времени
Это изобретательский, но он позволяет только взаимодействовать с кем-либо в модальном диалоговом окне за время, которое он открывает. Остальная часть браузера остается вешенной так же точно, как если бы вы просто вызвали зверский цикл while (new Date().getTime()<t1);
.
Модальное диалоговое окно более мягкое в цикле процессора и позволит избежать запуска сторожевого таймера script -execution-time в случае более длинных ожиданий, но вам придется балансировать это с раздражением отвлекающего диалогового окна с проблесковым открытием, а также не универсальную поддержку браузеров и проблему всех, кто ненавидит модальные диалоги!
Это будет похоже на спящий режим в течение небольшого периода времени, и я могу назвать это несколько раз, если это необходимо. Есть ли другой способ?
Чего вы на самом деле пытаетесь достичь спящим? Не возвращаясь к циклу событий или не запуская модальное диалоговое окно, вы не сможете получить какое-либо обновление на экране или взаимодействие с пользователем, поэтому я не вижу, что сделает встроенный сон для вас. Вы, конечно, не можете делать анимацию таким образом.
В Firefox вы получаете Python-стиль generators, который позволит вам написать процесс взаимодействия процедурного стиля с помощью yield
для возврата управления в браузер по мере необходимости. Это может улучшить простоту кода, поскольку вам не нужно переписывать условные и циклические структуры в качестве запоминаемого состояния в переменных. Однако, как поддерживают браузеры Mozilla, вы не можете использовать его в дикой природе в обозримом будущем.
ETA:
Я хочу написать ORM с sync api, чтобы разработчики могли использовать его более легко. Чтобы свести эту асинхронную синхронизацию к api, мне нужно что-то вроде сна.
Извините, не может быть сделано в общем случае. У базового JavaScript нет потоков, ко-подпрограмм или других примитивов, которые могут связывать синхронизацию и асинхронный код.
Спецификация базы данных веб-SQL основывается на браузерах, которые вызывают функцию обработки результатов (переданную в executeSql()
) в качестве обратного вызова браузера. Обратные вызовы браузера могут запускаться только тогда, когда управление прошло обратно в браузер, а не в синхронном потоке выполнения.
В теории вы можете открыть modalDialog, выполнить асинхронный вызов базы данных Web SQL внутри окна modalDialog
и иметь modalDialog вернуть результат в синхронный код в сценариях окна вызова. Однако в настоящее время нет браузера, который поддерживает как openDatabase
, так и openModalDialog
!
Ответ 6
Я знаю, что этот вопрос немного устарел, но у меня была аналогичная проблема, когда мне нужно было моделировать script, для загрузки на страницу было занято много времени. Я решил решить проблему, создав конечную точку на стороне сервера, которая ждала 5 секунд перед отправкой ответа, а затем добавила тег script в DOM, чтобы указать на это.
Конечно, для этого требуется реализация на стороне сервера, однако она позволяет остановить страницу в любой конкретной точке. Как уже говорили другие, это блокирует весь браузер, а не только ваш script.