Обновлено 22.06.2019
Добрый день! Уважаемые читатели и гости крупного IT блога России Pyatilistnik.org. В прошлый раз я вас научил делать резервную копию файлов и папок с помощью утилиты Robocopy. Сегодня я хочу вам рассказать еще об одной ситуации, которая случилась в моей административной практике, а именно по какой то причине скрипты и сценарии настроенные на вход пользователя в систему не отрабатывают сразу, а выполняются с задержкой в 5 минут. Мне стало интересно разобраться в данной ситуации и естественно поправить время выполнения моих скриптов. Думаю, что найдутся люди, кто так же зададутся данным вопросом.
Описание ситуации
Есть терминальная RDS ферма построенная на базе операционной системы Windows Server 2012 R2, состоящая из 15 RDSH хостов. Для удобства пользователей использующих программу 1С, был настроен через групповую политику скрипт, который при входе пользователя в систему должен был подтянуть конфигурационный файл с необходимым списком баз 1С. Но получилась такая ситуация, что пользователь заходит, видит свой рабочий стол, открывает программу 1С и баз там нет, через 5 минут, перезапустив 1С они магическим образом появляются. Давайте разбираться, что это за задержка и как от нее избавится.
Откуда берется 5-ти минутная задержка
Оказывается с выходом операционных систем Windows Server 2012 R2 и Windows 8.1 компания Microsoft ввела некоторое изменение с применением сценариев и скриптов при входе пользователя в систему. После входа пользователя на компьютер под управлением Windows 8.1 и Windows Server 2012 R2 сценарии входа не запускаются в течение пяти минут. Такое поведение вызывает следующие симптомы:
- Операции, выполняемые сценариями входа в систему, могут не отображаться на компьютерах под управлением Windows 8.1 и Windows Server 2012 R2 в течение пяти минут после входа пользователя в систему.
- Ресурсы, предоставляемые сценариями входа в систему, могут быть недоступны пользователям на компьютерах под управлением Windows 8.1 и Windows Server 2012 R2 в течение примерно пяти минут после входа пользователей.
https://support.microsoft.com/en-gb/help/2895815/logon-scripts-do-not-run-for-five-minutes-after-a-user-logs-on-to-a-wi
Microsoft ввела данную задержку из-за того, чтобы улучшить ситуацию, когда большое количество скриптов, сценариев, выполняемых при логине пользователя в систему вступают в конфликтную ситуацию, что он даже не может попасть на свой рабочий стол. Данная настройка называется » Настроить задержку сценария входа (Configure Logon Script Delay)». По умолчанию она имеет значение в 5 минут, этого достаточно, чтобы пользователь вошел в систему, которая успела прогрузить все из автозагрузки, после чего к нему можно применять сценарии.
Как убрать 5-ти минутную задержку выполнения сценариев при входе в систему
Так как у вас есть домен Active Directory и вы все настройки выполняете через групповую политику, то откройте редактор групповой политики, найдите нужное вам организационное подразделение, создайте там политику или измените существующую. Нужная нам настройка находится в разделе компьютера, переходим по пути:
Конфигурация компьютера — Политики — Административные шаблоны — Система — Групповая политика — Настроить задержку сценария входа (Computer Configuration — Administrative Templates — System — Group Policy — Configure Logon Script Delay)
Открываем политику «Настроить задержку сценария входа». Режимы работы:
- Если стоит значение по умолчанию, то будет отложенное выполнение скриптов через 5 минут
- Если выставлено значение отключено, то сценарии входа будут выполнятся сразу
- Если поставите 0, то так же политика будет отключена и все будет выполняться сразу при входе, именно данный вариант и советует сама Microsoft
- Так же вы можете выставить другое значение, вплоть до 1000 минут.
Сохраняем настройку и давайте посмотрим как будет применяться политика при входе пользователя Барбоскина на терминальную ферму. Для этого откройте журналы логов Windows. Нас будет интересовать журнал Microsoft-Windows-GroupPolicy/Operational. Зашел я на терминальный сервер в 18-42 минуты.
Событие 5324: Групповая политика получила уведомление Вход в систему от Winlogon для сеанса 11.
Событие с кодом ID 5351: Сеанс групповой политики возвращается к WinLogon
Событие с кодом ID 4117: Начат сеанс групповой политики
Событие с кодом ID 4117: Запуск обработки политики входа пользователя в систему для rootbarboskin.g. Идентификатор операции: {f61f8549-f12f-4306-a957-83000600000000}
/wp-content/uploads/2019/06/ID-4117-1.jpg»>
Событие с кодом ID 5340: Режим обработки групповой политики: Фоновый асинхронный
Событие с кодом ID: Попытка получения сведений об учетной записи
Событие с кодом ID 4017: Выполнение системного вызова для получения сведений об учетной записи
Событие с кодом ID 5017: Системный вызов для получения сведений об учетной записи завершен. Вызов обработан за 0 мс.
Событие с кодом ID 5320: Полученные сведения об учетной записи
Событие с кодом ID 4126: Групповая политика получает применимые GPO от контроллера домена.
Событие с кодом ID 4257: Начинается скачивание политик
Событие с кодом ID 5257: Политики успешно скачаны
Событие с кодом ID 5216: Политики успешно сохранены в локальное хранилище данных
Событие с кодом ID 5126: Групповая политика успешно получила применимые GPO от контроллера домена
Событие с кодом ID 5312: Список применимых объектов групповой политики
Событие с кодом ID 5016: Завершена обработка расширения Scripts
Событие с кодом ID 8001: Завершена обработка политики входа пользователя для barboskin.g за 1 с
Событие с кодом ID 5117: Сеанс групповой политики успешно завершен
Вот такой набор событий, который показывает вам, как применяются групповые политики к вашему пользователю, уверен, что благодаря данным событиям вы легко сможете отслеживать, есть ли у вас задержки при обработке сценариев входа пользователя в систему. Теперь у вас не должно быть 5-ти минутных задержек. На этом у меня все, с вами был Иван Семин, автор и создатель IT портала Pyatilistnik.org,
При использовании скриптов часто бывает необходимость установки интервала выполнения между одной частью программы и другой. Это можно назвать паузами, но чаще они имеют название содержащие sleep и такая же команда есть в Powershell. Один из примеров использования таких задержек — это поисковики. Когда мы часто выполняем запросы к одному сайту может появится каптча и что бы этого избежать нужно использовать задержку.
Синтаксис командлета следующий:
Start-Sleep -Seconds 5
Кроме длительности задержки в секундах мы можем указывать миллисекунды:
sleep -Milliseconds 5
Sleep — это алиас на основную команду.
Параметров для минут и часов нет, но вы можете выполнять такие операции в качестве выражений:
$timeout = 2
Sleep -Second ($timeout * 60)
Если вы хотите добавить больше логики командлету, например добавив параметр Hours (часы), можете создать функцию типа этой:
function Start-SleepMinutes ($Seconds, $Minutes, $Hours){
if ($Seconds){Start-Sleep -Seconds $Seconds}
elseif ($Minutes){Start-Sleep ($Minutes*60)}
elseif ($Hours){Start-Sleep ($Hours*60*60)}
}
Start-SleepMinutes -Seconds 2
Более подробно о создании функций в Powershell мы писали раннее.
Параметр по умолчанию секунды и он будет первый и он примет значения из конвейера, правда я не знаю кому это может понадобиться:
$timer = @(1,2,3,4)
$timer | sleep
Такую команду можно использовать для подсчета роста использования ресурсов каким-нибудь процессом:
$result = Get-Process -Name chrome | Measure-Object -Sum WS
sleep 10
$result2 = Get-Process -Name chrome | Measure-Object -Sum WS
$result.Sum - $result2.Sum
…
Теги:
#powershell
В JS для работы с «планированием вызова» существуют два метода:
1
Метод setInterval
Позволяет вызывать функцию много раз, через определённый интервал времени:
setInterval(func, delay)
Где:
func
– функция или строка кода для выполнения,delay
– интервал в миллисекундах (1000 = 1 секунда).
Стоит заметить, что вызываемая функция будет работать асинхронно.
Выполнение кода:
setInterval("alert('Прошла одна секунда');"}, 1000);
JS
Выполнение анонимной функции:
setInterval(function(){
alert('Прошла одна секунда');
}, 1000);
JS
Вызов функции:
setInterval('showmessage', 1000);
function showmessage(){
alert('Прошла одна секунда');
}
JS
Отмены выполнения
Чтобы остановить setInterval применяется метод clearInterval(id)
.
var interval_id = setInterval(function(){
alert('Прошла одна секунда');
}, 1000);
...
clearInterval(interval_id);
JS
2
Метод setTimeout
Выполняет заданный код асинхронно только один раз, через заданный интервал времени.
Синтаксис:
setTimeout(func, delay)
Где:
func
– функция или строка кода для выполнения,delay
– интервал в миллисекундах (1000 = 1 секунда).
Выполнение кода:
setTimeout("alert('1-секундная задержка прошла');", 1000);
JS
Выполнение анонимной функции:
setTimeout(function(){
alert('1-секундная задержка прошла');
}, 1000);
JS
Вызов функции:
setTimeout(showmessage, 1000);
function showmessage(){
alert('1-секундная задержка прошла');
}
JS
Также, метод setTimeout можно отменить с помощью метода clearTimeout(id)
.
var timeout_id = setTimeout(function(){
alert('1-секундная задержка прошла');
}, 1000);
...
clearTimeout(timeout_id);
JS
Опубликовано: 13.06.2017
Инструкция представляет шпаргалку по настройке автозапуска сценария при выполнении входа в систему Windows (login).
Настройка имеет некоторые нюансы, из-за которых, даже опытные системные администраторы не сразу могут понять причину неработоспособности сценария.
И так, запускаем консоль управления групповыми политиками и создаем новый объект GPO.
1. Разрешаем запуск скриптов.
Конфигурация компьютера Административные шаблоны Компоненты Windows Windows Powershell
(Computer Configuration Administrative Templates Windows Components Windows PowerShell)
Находим параметр Включить выполнение сценариев (Turn On Script Execution) и выставляем значение Включить и в выпадающем списке Разрешить все сценарии.
2. Настраиваем время задержки для выполнения скриптов.
Конфигурация компьютера Административные шаблоны Система Групповая политика
(Computer Configuration Administrative Templates System Group Policy)
Находим параметр Настроить задержку сценария входа в систему (Configure Logon Script Delay) и выставляем значение Включить и время задержки в минутах, например 1.
* как показала практика, лучше ставить хоть какую-то задержку.
3. Настраиваем автозапуск скрипта при входе.
Конфигурация компьютера (или Конфигурация пользователя) Политики Конфигурация Windows Сценарии
(Computer Configuration или User Configuration Policies Windows Settings Scripts)
В данной ветке мы увидим параметры для настройки сценария при входе или выходе из системы (включении или выключении компьютера). Дважды кликаем по нужному параметру и переходим на вкладку Сценарии Powershell (Powershell Scripts).
Нажимаем по Добавить и выбираем заранее написанный скрипт.
Если необходимо задать приоритет сценариям перед обычными сценариями, в выпадающем списке «Для этого объекта групповой политики выполните сценарии в следующем порядке» выбираем нужный пункт.
Была ли полезна вам эта инструкция?
Да Нет
(PHP 4, PHP 5, PHP 7, PHP
sleep — Задержка выполнения
Описание
sleep(int $seconds
): int
Откладывает исполнение программы на число секунд, указанное в параметре
seconds
.
Замечание:
Чтобы отложить выполнение программы на доли секунды,
используйте функцию usleep(), поскольку функция sleep()
ожидает целое число (int).
Например,sleep(0.25)
приостановит выполнение программы на0
секунд.
Список параметров
-
seconds
-
Время остановки в секундах (должно быть больше или равно
0
).
Возвращаемые значения
Возвращает 0 в случае успешного выполнения.
Если вызов был прерван сигналом, функция sleep()
возвратит значение, не равное нулю. В Windows это значение всегда будет
равно 192
(значение константы Windows API
WAIT_IO_COMPLETION
). На других платформах возвращаемом
значением будет количество секунд, оставшихся до задержки.
Ошибки
Если указанное число секунд в параметре seconds
отрицательное, выбрасывается исключение ValueError..
Список изменений
Версия | Описание |
---|---|
8.0.0 |
Функция выбрасывает исключение ValueError, если в параметре seconds указано отрицательное число;ранее вместо этого выдавалась ошибка уровня E_WARNING и функция возвращала значение false .
|
Примеры
Пример #1 Пример использования sleep()
<?php// текущее время
echo date('h:i:s') . "n";// ожидание в течениe 10 секунд
sleep(10);// завершение ожидания
echo date('h:i:s') . "n";?>
Этот пример выведет (через 10 секунд)
Смотрите также
- usleep() — Задержка выполнения в микросекундах
- time_nanosleep() — Задержка на заданное число секунд и наносекунд
- time_sleep_until() — Откладывает исполнение скрипта до заданного времени
- set_time_limit() — Ограничение времени выполнения скрипта
ash b ¶
8 years ago
re: "mitigating the chances of a full bruit force attack by a limit of 30 lookups a minute."
Not really - the attacker could do 100 requests. Each request might take 2 seconds but it doesn't stop the number of requests done. You need to stop processing more than one request every 2 seconds rather than delay it by 2 seconds on each execution.
Anonymous ¶
4 years ago
Diego Andrade's msleep function is not compatible with php7's `strict_types`, cast the usleep parameter to int, and it will be,
usleep((int)($time * 1000000));
barlow at fhtsolutions dot com ¶
11 years ago
You should put sleep into both the pass and fail branches, since an attacker can check whether the response is slow and use that as an indicator - cutting down the delay time. But a delay in both branches eliminates this possibility.
MPHH ¶
19 years ago
Note: The set_time_limit() function and the configuration directive max_execution_time only affect the execution time of the script itself. Any time spent on activity that happens outside the execution of the script such as system calls using system(), the sleep() function, database queries, etc. is not included when determining the maximum time that the script has been running.
Diego Andrade ¶
7 years ago
Maybe obvious, but this my function to delay script execution using decimals for seconds (to mimic sleep(1.5) for example):
<?php
/**
* Delays execution of the script by the given time.
* @param mixed $time Time to pause script execution. Can be expressed
* as an integer or a decimal.
* @example msleep(1.5); // delay for 1.5 seconds
* @example msleep(.1); // delay for 100 milliseconds
*/
function msleep($time)
{
usleep($time * 1000000);
}
?>
hartmut at six dot de ¶
22 years ago
it is a bad idea to use sleep() for delayed output effects as
1) you have to flush() output before you sleep
2) depending on your setup flush() will not work all the way to the browser as the web server might apply buffering of its own or the browser might not render output it thinks not to be complete
netscape for example will only display complete lines and will not show table parts until the </table> tag arrived
so use sleep if you have to wait for events and don't want to burn to much cycles, but don't use it for silly delayed output effects!
Anonymous ¶
8 years ago
If you are having issues with sleep() and usleep() not responding as you feel they should, take a look at session_write_close()
as noted by anonymous on comments;
"If the ajax function doesn't do session_write_close(), then your outer page will appear to hang, and opening other pages in new tabs will also stall."
ealexs at gmail dot com ¶
4 months ago
From my testing calling sleep(0); will do a `thread spin`.
It would be nice if this was to be put explicitly in the documentation as it is useful. You can do the minimum wait without overloading the CPU thread.
Anonymous ¶
1 year ago
I wrote a simple method for sleeping with a float, which also allows you to do milliseconds (via fractional seconds).
<?php
function sleepFloatSecs($secs) {
$intSecs = intval($secs);
$microSecs = ($secs - $intSecs) * 1000000;
if(
$intSecs > 0) {
sleep($intSecs);
}
if($microSecs > 0) {
usleep($microSecs);
}
}
?>
And testing on my machine it works perfectly:
<?php
$x = [0.100,0.250,0.5,1.0,1.5,2.0,2.5];
foreach(
$x as $secs) {
$t = microtime(true);
sleepFloatSecs($secs);
$t = microtime(true) - $t;
echo "$secs t => t $tn";
}
?>
Output:
<?php
0.1 => 0.10017800331116
0.25 => 0.25016593933105
0.5 => 0.50015211105347
1 => 1.0001430511475
1.5 => 1.5003218650818
2 => 2.000167131424
2.5 => 2.5002470016479
?>
LVT ¶
9 years ago
Always close your SQL connection and free the memory before using sleep( ) or you will be needlessly holding a SQL connection for [xx] seconds, remember that a shared hosting environment only allows max 30 SQL connections at the same time.
joshmeister at gmail dot com ¶
10 years ago
Here is a simplified way to flush output to browser before completing sleep cycle. Note the buffer must be "filled" with 4096 characters (bytes?) for ob_flush() to work before sleep() occurs.
<?php
ob_implicit_flush(true);
$buffer = str_repeat(" ", 4096);
echo "see this immediately.<br>";
echo $buffer;
ob_flush();
sleep(5);
echo "some time has passed";
?>
jimmy at powerzone dot dk ¶
12 years ago
Notice that sleep() delays execution for the current session, not just the script. Consider the following sample, where two computers invoke the same script from a browser, which doesn't do anything but sleep.
PC 1 [started 14:00:00]: script.php?sleep=10 // Will stop after 10 secs
PC 1 [started 14:00:03]: script.php?sleep=0 // Will stop after 7 secs
PC 2 [started 14:00:05]: script.php?sleep=0 // Will stop immediately
http://php.net/session_write_close may be used to address this problem.
Anonymous ¶
13 years ago
This will allow you to use negative values or valuer below 1 second.
<?php slaap(0.5); ?>
<?php
function slaap($seconds)
{
$seconds = abs($seconds);
if ($seconds < 1):
usleep($seconds*1000000);
else:
sleep($seconds);
endif;
}
?>
manu7772 at gmail dot com ¶
1 year ago
Sleep method with parameter in milliseconds :
public static function ms_sleep($milliseconds = 0) {
if($milliseconds > 0) {
$test = $milliseconds / 1000;
$seconds = floor($test);
$micro = round(($test - $seconds) * 1000000);
if($seconds > 0) sleep($seconds);
if($micro > 0) usleep($micro);
}
}
sergio at inbep dot com dot br ¶
6 years ago
To use float or int numbers
function pause($seconds)
{
usleep($seconds * 1000000);
}
pause(0.25);
f dot schima at ccgmbh dot de ¶
13 years ago
Remember that sleep() means "Let PHP time to do some other stuff".
That means that sleep() can be interrupted by signals. That is important if you work with pcntl_signal() and friends.
toddjt78 at msn dot com ¶
12 years ago
Simple function to report the microtime since last called or the microtime since first called.
<?php
function stopWatch($total = false,$reset = true){
global $first_called;
global $last_called;
$now_time = microtime(true);
if ($last_called === null) {
$last_called = $now_time;
$first_called = $now_time;
}
if ($total) {
$time_diff = $now_time - $first_called;
} else {
$time_diff = $now_time - $last_called;
}
if ($reset)
$last_called = $now_time;
return $time_diff;
}
?>
$reset - if true, resets the last_called value to now
$total - if true, returns the time since first called otherwise returns the time since last called
code {@} ashleyhunt [dot] co [dot] uk ¶
11 years ago
A really simple, but effective way of majorly slowing down bruit force attacks on wrong password attempts.
In my example below, if the end-user gets the password correct, they get to log in at full speed, as expected. For every incorrect password attempt, the users response is delayed by 2 seconds each time; mitigating the chances of a full bruit force attack by a limit of 30 lookups a minute.
I hope this very simple approach will help make your web applications that little bit more secure.
Ashley
<?php
public function handle_login() {
if($uid = user::check_password($_REQUEST['email'], $_REQUEST['password'])) {
return self::authenticate_user($uid);
}
else {
// delay failed output by 2 seconds
// to prevent bruit force attacks
sleep(2);
return self::login_failed();
}
}
?>
LVT ¶
9 years ago
Another reason for not to abuse sleep( ) is that along with the maximum of 30 sql connections, a shared hosting environment usually limits the number of processes to 20, if your website has many users online and you put sleep( ) everywhere in the code, your server will throw a 508 error (resource limit reached) and will stop serving your website.
soulhunter1987 at post dot ru ¶
12 years ago
Since sleep() can be interrupted by signals i've made a function which can also be interrupted, but will continue sleeping after the signal arrived (and possibly was handled by callback). It's very useful when you write daemons and need sleep() function to work as long as you 'ordered', but have an ability to accept signals during sleeping.
<?php
function my_sleep($seconds)
{
$start = microtime(true);
for ($i = 1; $i <= $seconds; $i ++) {
@time_sleep_until($start + $i);
}
}
?>
smcbride at msn dot com ¶
1 year ago
An example of using sleep to run a set of functions at different intervals. This is not a replacement for multi-threading, but it could help someone that wants to do something cheap. You don't have to use eval(). It is just used as an example. This is different than running a standard 1 second sleep loop, due to sleeping longer does not consume as much CPU.
<?php// current time
echo date('h:i:s') . "n";// Some example functions
function function_a() { echo 'function_a called @ ' . date('h:i:s') . PHP_EOL; }
function function_b() { echo 'function_b called @ ' . date('h:i:s') . PHP_EOL; }
function function_c() { echo 'function_c called @ ' . date('h:i:s') . PHP_EOL; }// Add some timers (in seconds) with function calls
$sleeptimers = array();
$sleeptimers['5'][0]['func'] = 'function_a();';
$sleeptimers['10'][0]['func'] = 'function_b();';
$sleeptimers['15'][0]['func'] = 'function_c();';// Process the timers
while(true) {
$currenttime = time();
reset($sleeptimers);
$mintime = key($sleeptimers);
foreach($sleeptimers as $SleepTime => $Jobs) {
foreach($Jobs as $JobIndex => $JobDetail) {
if(!isset($JobDetail['lastrun'])) {
$sleeptimers[$SleepTime][$JobIndex]['lastrun'] = time();
if($SleepTime < $mintime) $mintime = $SleepTime;
} elseif(($currenttime - $JobDetail['lastrun']) >= $SleepTime) {
eval($JobDetail['func']);
$lastrun = time();
$sleeptimers[$SleepTime][$JobIndex]['lastrun'] = $lastrun;
$mysleeptime = $SleepTime - ($currenttime - $lastrun);
if($mysleeptime < 0) $mysleeptime = 0;
if(($currenttime - $JobDetail['lastrun']) < $mintime) $mintime = $mysleeptime; // account for length of time function runs
echo 'Sleep time for function ' . $JobDetail['func'] . ' = ' . $mysleeptime . PHP_EOL;
}
}
}
echo 'Sleeping for ' . $mintime . ' seconds' . PHP_EOL;
sleep($mintime);
}?>
webseos at gmail dot com ¶
14 years ago
This is a critical thing to use time delay function as sleep() Because a beginner can find that this is not working and he/she will see that all output appearing at a time.
A good way to implement this is by using the function - ob_implicit_flush() then you don't need to use flush() function explicitly.
A sample code :
<?php
ob_implicit_flush(true);
for($i=0;$i<5;$i++)
{
$dis=<<<DIS
<div style="width:200px; background-color:lime;border:1px; text-align:center;text-decoration:blink;">
$i
</div>
DIS;
echo $dis;sleep(5);
//flush();
}
mohd at Bahrain dot Bz ¶
13 years ago
I hope this code will help somebody to solve the problem of not being able to flush or output the buffer to the browser (I use IE7).
It may work for you with just [ echo str_repeat(".", 4096); ] and without even using ob_... and flush.
<?php
ob_start();ob_implicit_flush(true);
//[ OR ] echo "..."; ob_flush(); flush();set_time_limit(0);
function
sleep_echo($secs) {
$secs = (int) $secs;
$buffer = str_repeat(".", 4096);
//echo $buffer."rn<br />rn";
for ($i=0; $i<$secs; $i++) {
echo date("H:i:s", time())." (".($i+1).")"."rn<br />rn".$buffer."rn<br />rn";
ob_flush();
flush();
sleep(1);
//usleep(1000000);
}
}sleep_echo(30);ob_end_flush();
?>
Многие языки программирования имеют функцию сна, которая будет задерживать выполнение программы на несколько секунд. Однако эта функциональность отсутствует в JavaScript из-за ее асинхронного характера.
В этой статье, мы кратко рассмотрим почему так может быть, а затем как мы можем реализовать функцию сна самостоятельно.
Понимания модели исполнения JavaScript
Перед тем, как мы приступим, важно убедится, что мы правильно понимаем модель выполнения JavaScript.
Рассмотрим следующий код Ruby:
require 'net/http' require 'json' url = 'https://api.github.com/users/jameshibbard' uri = URI(url) response = JSON.parse(Net::HTTP.get(uri)) puts response['public_repos'] puts "Hello!"
Как и следовало ожидать, этот код отправляет запрос к GitHub API для получения моих пользовательских данных. Затем он анализирует ответ, выводит количество открытых репозиториев, относящихся к моей учетной записи GitHub, и, наконец, выводит на экран «Hello!». Исполнение идет сверху вниз.
Сравните его с эквивалентной версией в JavaScript:
fetch('https://api.github.com/users/jameshibbard') .then(res => res.json()) .then(json => console.log(json.public_repos)); console.log("Hello!");
Если вы запустите этот код, он выведет «Hello!» На экран, а затем количество публичных репозитеров, связанных с моей учетной записью GitHub.
Это связано с тем, что выборка данных из API является асинхронной операцией в JavaScript. Интерпретатор JavaScript встретит команду fetch и отправит запрос. Однако, он не будет ждать завершения запроса. Скорее всего, он продолжит свой путь, выведет «Hello!» на консоль, а затем, когда запрос вернется через пару сотен миллисекунд, выдаст количество репозитеров.
Возможно, Вам не нужна функция сна
Теперь, когда мы лучше понимаем модель выполнения JavaScript, давайте посмотрим, как JavaScript обрабатывает задержки и асинхронные операции.
Создание простой задержки, используя setTimeout
Стандартный способ создания задержки в JavaScript это использовать метод setTimeout. Например:
console.log("Hello"); setTimeout(() => { console.log("World!"); }, 2000);
Он будет показывать «Hello!» на консоли, а затем через две секунд «World!». И во многих случаях этого достаточно: сделать что-то, подождать, затем сделать что-то еще. Выполнено!
Однако, имейте ввиду, что метод setTimeout асинхронный. Попробуйте изменить предыдущий код следующим образом:
console.log("Hello"); setTimeout(() => { console.log("World!"); }, 2000); console.log("Goodbye!");
Оно покажет это:
Hello Goodbye! World!
В ожидании вещей с setTimeout
Также возможно использовать setTimeout (или его двоюродного брата setInterval), чтобы заставить JavaScript ждать пока не будет выполнено условие. Например, вот как вы можете использовать setTimeout, чтобы дождаться появления определенного элемента на веб-странице:
function pollDOM () { const el = document.querySelector('my-element'); if (el.length) { // Do something with el } else { setTimeout(pollDOM, 300); // try again in 300 milliseconds } } pollDOM();
Это предполагает, что элемент появится в какой-то момент. Если вы не уверены, что это так, вам нужно посмотреть на отмену таймера (используя clearTimeout или clearInterval).
Управление потоком в современном JavaScript
При написании JavaScript часто бывает необходимо подождать, пока что-то произойдет (например, данные должны быть получены из API), а затем сделать что-то в ответ (например, обновить пользовательский интерфейс для отображения данных).
В приведенном выше примере используется функция анонимного обратного вызова, но если Вам нужно подождать пока произойдет несколько событий, синтаксис быстро становится довольно грубым, и вы попадаете в ад обратного вызова.
К счастью, язык значительно изменился за последние несколько лет и предлагает нам новые конструкции, чтобы избежать этого.
Например, используя асинхронное ожидание, мы можем переписать исходный код, чтобы получить информацию из GitHub API:
(async () => { const res = await fetch(`https://api.github.com/users/jameshibbard`); const json = await res.json(); console.log(json.public_repos); console.log("Hello!"); })();
Теперь код будет выполнятся с верху вниз. Интерпретатор JavaScript ожидает завершение сетевого запроса, и сначала регистрирует количество открытых репозитеров, а затем сообщение «Hello!».
Сон в изначальном JavaScript
Если вы все еще читаете, вы вполне готовы заблокировать поток выполнения и заставить JavaScript ждать его.
Вот как вы можете это сделать:
function sleep(milliseconds) { const date = Date.now(); let currentDate = null; do { currentDate = Date.now(); } while (currentDate - date < milliseconds); } console.log("Hello"); sleep(2000); console.log("World!");
Как и ожидалось, сначала отобразится «Hello», затем будет пауза в две секунды, затем отобразится «World!»
Он работает с помощью метода Date.now, чтобы получить количество миллисекунд, прошедших с 1 января 1970 года, и присвоить это значение переменной дате. После он создает пустую переменную currentDate перед входом в цикл do … while. В цикле он многократно получает количество миллисекунд, прошедших 1 января 1970 года, и присваивает значение ранее объявленной переменной currentDate. Цикл будет продолжаться, пока разница между date и currentDate будет меньше желаемой задержки в миллисекунд.
Работа выполнена, не так ли? Ну, не совсем…
Лучшая функция сна
Может этот код делает в точности то, на что Вы надеялись он будет делать, но имейте ввиду, у него есть большой недостаток: цикл будет блокировать поток выполнения JavaScript и гарантировать, что никто не сможет взаимодействовать с вашей программой до ее завершения. Если вам нужна большая задержка, есть вероятность, что это может даже привести к поломке.
Так что делать?
Ну, также возможно объединить методы, изученные ранее в статье, чтобы сделать менее навязчивую функцию сна:
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } console.log("Hello"); sleep(2000).then(() => { console.log("World!"); });
Этот код будет отображать «Hello!», затем пауза на две секунды, затем отобразит «World!». Незримо для окружающих, мы используем метод setTimeout, для разрешения Promise через заданное количество миллисекунд.
Обратите внимание, что нам нужно использовать обратный вызов then, чтобы убедится, что второе сообщение записывается задержкой. Мы также можем связать больше обратных вызовов на первый:
console.log("Hello"); sleep(2000) .then(() => { console.log("World!"); }) .then(() => { sleep(2000) .then(() => { console.log("Goodbye!"); }) });
Это работает, но выглядит некрасиво. Мы можем сделать это с помощью async … await:
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function delayedGreeting() { console.log("Hello"); await sleep(2000); console.log("World!"); await sleep(2000); console.log("Goodbye!"); } delayedGreeting();
Это выглядит хорошо, но означает, что любой код, использующий функцию сна, должен быть помечен как асинхронный.
Конечно, оба этих метода по-прежнему имеют недостаток (или особенность) в том, что они не приостанавливают выполнение всей программы. Спит только Ваша функция:
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function delayedGreeting() { console.log("Hello"); await sleep(2000); console.log("World!"); } delayedGreeting(); console.log("Goodbye!");
Код выше регистрирует следующее:
Hello Goodbye! World!
Вывод
Проблемы синхронизации в JavaScript являются причиной головных болей для многих разработчиков, и то, как Вы справляетесь с ними, зависит от того, чего Вы пытаетесь достичь.
Хотя функция сна присутствует во многих других языках, я рекомендую вам принять асинхронную природу JavaScript и стараться не бороться с языком. Это на самом деле, довольно приятно, когда Вы привыкните к этому.
Понравилось то, что вы прочитали?
Подписывайтесь на нашу рассылку и получайте ежедневные обновления о новых учебниках, статьях, курсах и о многом другом!
Просто введите ваш адрес электронной почты, чтобы подписаться.
(Без спамов; ежемесячно два письма; отписаться от рассылки можно в любое время)
Во многих языках программирования есть функция sleep, которая может задерживать
выполнение программы на несколько секунд. Но в JavaScript такая функция отсутствует из-за его асинхронного
характера. В этой статье мы рассмотрим как реализовать js sleep самостоятельно.
setTimout и sleep в JavaScript
Для того, чтобы лучше понять проблему, посмотрите следующий код. Он делает запрос к API GitHub для получения
пользовательских данных, затем выводит количество публичных репозиториев и, наконец, пошлет в консоль «Привет!»
JS
fetch('https://api.github.com/users/username')
.then(res => res.json())
.then(json => console.log(json.public_repos));
console.log("Привет!");
Но если запустить такой код, то сначала он выведет на экран «Привет!», а уже потом количество публичных
репозиториев.
Так происходит, потому что получение данных от API — это асинхронная операция в JavaScript. Интерпритатор
JavaScript встретит команду fetch и отправит запрос. Он не будет ждать завершения
запроса и выведет «Привет!» в консоль, и потом через пару сотен миллисекунд выдаст количество рекозиториев.
Создаем простую задержку с помощью js setTimeout
Теперь, давайте рассмотрим создание задержки в JavaScript, используя метод setTimeout.
JS
console.log("Привет");
setTimeout(() => { console.log("мир"); }, 3000);
Этот код запишет в консоль «Привет», а затем через 3 секунды «мир» ‐ во многих случаях такой задержки
достаточно. Но имейте ввиду, что в js setTimeout ‐ это асинхронный метод. Попробуйте
изменить предыдущий код следующим образом:
JS
console.log("Привет");
setTimeout(() => { console.log("мир"); }, 3000);
console.log("Пока");
Этот код выведет: Привет Пока мир.
Вы также можете использовать setTimeout (или его брата setInterval),
чтобы заставить JavaScript подождать пока не будет выполнено какое-либо условие. К примеру, вам нужно дождаться
появления определенного элемента на странице:
JS
function waitForDOM () {
const container = document.querySelector('container');
if (container.length) {
// Делаем что-то с контейнером
} else {
setTimeout(waitForDOM, 300); // Попробовать снова через 300 миллисекунд
}
}
waitForDOM();
Управление потоком в современном JavaScript
В JavaScript часто бывают ситуации, когда вам нужно подождать, пока то-то произойдет, а затем сделать что-то в
ответ. В примере выше мы использовали анонимную callback функцию. Но что если вам нужно подождать несколько событий?
В этом случае синтаксис быстро становится довольно грубым.
К счастью, язык значительно изменился за последние несколько лет и теперь у нас есть новые конструкции для этих
целей. К примеру, мы может переписать код для получения информации из API GitHub, используя async await.
JS
(async () => {
const res = await fetch(`https://api.github.com/users/username`);
const json = await res.json();
console.log(json.public_repos);
console.log("Привет!");
})();
Теперь код выполняется сверху вниз.
Sleep в JavaScript
Мы уже готовы остановить поток выполнения программы и заставить JavaScript спать. Вот как мы можем это сделать:
JS
function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}
console.log("Привет");
sleep(2000);
console.log("мир");
В результате сначала в консоли отобразится «Привет», пауза на две секунды, а затем «мир». Функция работает с помощью
метода Date.now, получает количество миллисекунд, прошедших с 1 января 1970
года, и присваивает это значение переменной date. Запускает цикл, который будет
продолжаться, пока разница
между date и currentDate будет меньше нужной задержки.
Улучшаем функцию js sleep
Функция делает то, что нам нужно, но у нее есть недостаток: если вам нужна большая задержка, то она может привести к
поломке программы. Объединим методы изученные ранее в статье, чтобы сделать менее навязчивую функцию сна.
JS
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
console.log("Привет");
sleep(2000).then(() => { console.log("мир"); });
Этот код выведет в консоль «Привет», подождет 2 секунды, затем выведет «мир». Внутри мы используем Promise.
Сделаем JavaScript функцию sleep с помощью async … await:
JS
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function delayedGreeting() {
console.log("Привет");
await sleep(2000);
console.log("мир");
}
delayedGreeting();
console.log("Пока");
Материал из Справочник Web-языков
Перейти к: навигация, поиск
Содержание
- 1 set_time_limit
- 2 sleep
- 3 usleep
- 4 die
- 5 exit
- 6 assert
- 7 assert_options
- 8 eval
set_time_limit
Установка предельного времени исполнения сценария.
Синтаксис:
void set_time_limit(int seconds)
При запуске сценария PHP запускает системный таймер, и если время (выделенное сценарию для выполнения) истекает, а сценарий еще не завершился, PHP принудительно завершает сценарий (генерируя фатальную ошибку исполнения). Это не допускает скопления большого количества сценариев, расходующих ресурсы сервера, но, повидимому, «зависших» (например, если в них обнаружился бесконечный цикл или они пытаются дождаться подключения к не отвечающему серверу).
По умолчанию допустимое время исполнения сценария устанавливается в файле конфигурации параметром max_execution_time (обычно оно равно 30 с). Но для текущего сценария это время можно изменить вызовом данной функции, указав время в секундах в ее аргументе. Если указывается значение 0, то тогда временное ограничение снимается.
Отсчет времени начинается от момента вызова функции. Например, если сценарий уже выполнялся в течении 15 секунд, а затем вызывается функция set_time_limit(20), то общее максимальное время исполнения сценария становится равным 35 секундам.
Если сценарий выполняется в безопасном режиме (с установленным параметром safe mode), то тогда вызов этой функции игнорируется и используется значение из файла конфигурации.
sleep
Задержка выполнения сценария.
Синтаксис:
void sleep(int seconds);
Фукция sleep() выполняет задержку выполнения сценария в секундах (seconds).
usleep
Задержка выполнения сценария в микросекундах.
Синтаксис:
void usleep(int micro_seconds);
Задержка выполнения сценария в микросекундах (micro_seconds).
Эта функция не работает в Windows.
die
Вывод сообщения и завершение текущего сценария.
Синтаксис:
void die(string message);
Эта функция выводит сообщение и прекращает выполнение текущего скрипта. Не возвращает значение.
<?php $filename = '/path/to/data-file'; $file = fopen($filename, 'r') or die "unable to open file ($filename)"; ?>
exit
Завершает текущий сценарий.
Синтаксис:
void exit(void);
Эта функция завершает текущий сценарий. Не возвращает значение.
assert
Проверка истинности значения.
Синтаксис:
int assert(string|bool assertion);
В качестве аргумента функции может быть указано значение или строка, содержащая код PHP (как в функции eval()). Функция проверяет, является ли значение (или выражение) равным false, и, если это так, выполняет определенные действия.
Поведение функции определяется установками в файле конфигурации или при вызове функции assert_options().
Обычно эта функция используется исключительно в целях отладки, для проверки тех значений, которые всегда должны быть истинны (например: подключение модуля, свободное пространство на диске и т.д.).
В целом же выполнение сценария не должно зависеть от таких проверок, а использовать обычные проверки возвращаемых функциями значений.
<?php function handler() { echo "n* Failed * n"; } assert("$a='1';"); echo "a: $a n"; assert(0); // завершать сценарий echo assert_options(ASSERT_BAIL, 1); // вызвать обработчик assert_options(ASSERT_CALLBACK, "handler"); // не выдавать сообщений PHP @assert(--$a); // эта строка не будет выполнена echo "n ... n"; ?>
Приведенный пример выведет:
a: 1 Warning: Assertion failed in file.php on line 20 0 * Failed *
assert_options
Определение параметров assert.
Синтаксис:
mixed assert_options(int parameter [, mixed value])
Эта функция позволяет определить поведение конструкции assert().
Возвращается предыдущее значение параметра (или значение false при ошибке), указанного в первом аргументе одной из следующих констант:
Параметр | ini-параметр | Умолчание | Описание |
ASSERT_ACTIVE | asser.active | 1 | Разрешить указание кода в assert(). |
ASSERT_WARNING | assert.warning | 1 | Выдавать предупреждение PHP. |
ASSERT_BAIL | assert.bail | 0 | Завершать выполнение, если «неистинно». |
ASSERT_QUIET_EVAL | assert.quiet_eval | 0 | Не выдавать сообщений. |
ASSERT_CALLBACK | assert_callback | (null) | Установить функцию в качестве обработчика «неистинных» assert(). |
Если значение необходимо переопределить, его указывают во втором аргументе.
eval
Производит выполнение строки содержащей PHP код.
Синтаксис:
void eval(string code_str);
Функция eval() производит выполнение строки, заданной в code_str содержащей PHP код. Кстати, это может пригодиться для сохранения кода в текстовом поле базы данных для более позднего выполнения. Не забывайте, что указанный в строке код должен быть синтаксически правильным (например, должны присутствовать точки с запятой после каждой команды и т.п.), в противном случае сценарий будет завершен в этой строке с ошибкой. Учитывайте также, что те значения переменных, которые будут установлены в данной строке, будут использоваться в оставшейся части сценария.
При изменении переменных значений в eval() эти переменные будут изменены и в основных данных.
Если в строке указан оператор return, то тогда выполнение указанного кода будет досрочно завершено и возвращенное значение можно будет получить как значение, возвращаемое самой функции.
<?php $string = 'cup'; $name = 'coffee'; $str = 'This is a $string with my $name in it. '; echo $str; eval( "$str = "$str";" ); echo $str; ?>
Результатом выполнения этого кода будет:
This is a $string with my $name in it. This is a cup with my coffee in it.