Виконати сценарій після конкретної затримки за допомогою JavaScript


189

Чи існує якийсь метод JavaScript, подібний до jQuery delay()або wait()(для затримки виконання сценарію на певний час)?

Відповіді:


189

Є наступне:

setTimeout(function, milliseconds);

функція, яка може пройти час, після якого функція буде виконуватися.

Див.: Віконний setTimeout()метод .


3
Це не вираз, який виконується, це функція. Відповідь @Marius ілюструє це.
педрофурла

117
це не затримка, це виделка. Затримка повинна працювати в одній нитці.
DragonLord

13
Це негайно виконає function_reference. Щоб "працювати" (асинхронно), слід вказати як: setTimeout (function () {MethodToCall ();}, 1000);
Bernoulli IT

6
Я хочу зазначити, що ми говоримо про JavaScript; виведення "потоків" або що це повинно працювати "синхронно" може бути правдивим технічно і семантично, але насправді не вписується в контекст JavaScript, враховуючи, що дійсно немає можливості досягти затримки жодним із цих методів (ви цього не робите " t створюйте "потоки" в JS, як і в інших мовах). Крім того, це не буде виконано відразу, function_referenceякщо ви не включите (). Тобто function_referenceсаме це - довідка; передача function_reference()вперед викликає функцію негайно.
Danny Bullis

237

Просто для додання того, про що говорили всі інші setTimeout: Якщо ви бажаєте в майбутньому викликати функцію з параметром, вам потрібно встановити деякі анонімні дзвінки функції.

Вам потрібно передати функцію як аргумент, щоб вона була викликана пізніше. Фактично це означає без дужок за назвою. Нижче перелічено повідомлення одразу, і він відобразить "Привіт світ":

var a = "world";
setTimeout(alert("Hello " + a), 2000);

Щоб виправити це, ви можете або ввести ім'я функції (як це робив Flubba), або ви можете використовувати анонімну функцію. Якщо вам потрібно передати параметр, вам доведеться використовувати анонімну функцію.

var a = "world";
setTimeout(function(){alert("Hello " + a)}, 2000);
a = "Stack Overflow";

Але якщо ви запустите цей код, ви помітите, що через 2 секунди спливаюче вікно скаже «Hello Stack Overflow». Це тому, що значення змінної a змінилося за ці дві секунди. Щоб сказати "Hello world" через дві секунди, вам потрібно використовувати такий фрагмент коду:

function callback(a){
    return function(){
        alert("Hello " + a);
    }
}
var a = "world";
setTimeout(callback(a), 2000);
a = "Stack Overflow";

Він зачекає 2 секунди, а потім спливає "Привіт, світ".


37

Просто щоб трохи розширити ... Ви можете виконати код безпосередньо під час setTimeoutвиклику, але як @patrick говорить , ви зазвичай призначаєте функцію зворотного дзвінка, як це. Час - мілісекунди

setTimeout(func, 4000);
function func() {
    alert('Do stuff here');
}

27

Якщо ви дійсно хочете мати функцію блокування (синхронну) delay(для чого б то не було), чому б не зробити щось подібне:

<script type="text/javascript">
    function delay(ms) {
        var cur_d = new Date();
        var cur_ticks = cur_d.getTime();
        var ms_passed = 0;
        while(ms_passed < ms) {
            var d = new Date();  // Possible memory leak?
            var ticks = d.getTime();
            ms_passed = ticks - cur_ticks;
            // d = null;  // Prevent memory leak?
        }
    }

    alert("2 sec delay")
    delay(2000);
    alert("done ... 500 ms delay")
    delay(500);
    alert("done");
</script>

2
Складність цього рішення полягає в тому, що він активно використовує процесор, що призводить до збільшення енергоспоживання та зменшення ресурсів, доступних для інших потоків / процесів (наприклад, інших вкладок, інших програм). Сон, навпаки, тимчасово припиняє використання потоком системних ресурсів потоком.
ramcdougal

1
краще використовувати Date.now () замість нової дати () і не думайте про витоки пам’яті
WayFarer

1
Звичайно, це інтенсивний процесор, але для швидкого і брудного тестування він працює
Maris B.

Я хочу його версію, яка не блокує нитку, тому я можу оновити DOM перед тим, delayяк відповісти на це запитання ). Чи можна це зробити?
Гі Імамура

3
Більш компактна процедура: затримка функції (мс) {var start_time = Date.now (); while (Date.now () - start_time <ms); }
герцог

15

Вам потрібно використовувати setTimeout і передати йому функцію зворотного дзвінка. Причина, коли ви не можете використовувати сон у javascript, полягає в тому, що ви заблокували всю сторінку тим часом нічого не робити. Не гарний план. Використовуйте модель події Javascript і залишайтеся щасливими. Не боройтеся з цим!


2
Все-таки це було б корисно для тестування. Як і затримка надсилання форми на кілька секунд, щоб оцінити зміни сторінки до того, як буде зроблено новий запит HTTP.
rushinge

1
@rushinge потім встановити зворотній дзвінок, щоб надіслати форму та відключити подання форми за замовчуванням
Populus

1
Погана ідея залишати посилання як код ... так як зараз це не працює.
Еммет Арріс

1
Або ви знаєте, я міг би це просто виправити.
Патрік

14

Ви також можете скористатися window.setInterval (), щоб регулярно запускати деякий код.


2
setInterval () не слід використовувати натомість слід використовувати setTimeout
пауль

9
setTimeout()робить це один раз, setInterval()робить це повторно. Якщо ви хочете, щоб ваш код працював кожні 5 секунд, setInterval()він робиться для роботи.
rcoup

11

Щоб додати до попередніх коментарів, я хотів би сказати наступне:

The setTimeout()Функція в JavaScript не зупиняє виконання сценарію на собі, а лише говорить компілятору , щоб виконати код коли - небудь в майбутньому.

Не існує функції, яка фактично може призупинити виконання, вбудоване в JavaScript. Однак ви можете написати власну функцію, яка робить щось на кшталт безумовного циклу до досягнення часу, скориставшись Date()функцією та додавши необхідний інтервал часу.


11

Якщо вам потрібно лише перевірити затримку, ви можете скористатися цим:

function delay(ms) {
   ms += new Date().getTime();
   while (new Date() < ms){}
}

І тоді, якщо ви хочете затримати на 2 секунди, ви робіть:

delay(2000);

Хоча це може бути не найкращим для виробництва. Детальніше про це в коментарях


@ U2744 SNOWFLAKE Ви можете спробувати бути трохи точнішими у своєму коментарі
Christoffer

1
Ну, це зайнятий контур, який буде розряджати акумулятори ноутбуків та інших мобільних пристроїв, а також, ймовірно, також запобігає реагуванню (або навіть показу) інтерфейсу користувача.
Ри-

@ U2744SNOWFLAKE Має сенс. Оновили відповідь, для чого я використовував цю функцію :)
Крістофер

2
Досить добре працює в розробці для швидкого і брудного (і тимчасового) рішення.
HumanInDisguise

5

чому ти не можеш поставити код за обіцянкою? (набрана вгорі голови)

new Promise(function(resolve, reject) {
  setTimeout(resolve, 2000);
}).then(function() {
  console.log('do whatever you wanted to hold off on');
});


5

Проста відповідь:

setTimeout(
    function () {
        x = 1;
    }, 1000);

Наведена вище функція чекає 1 секунди (1000 мс), а потім встановлює х на 1. Очевидно, що це приклад; ви можете робити все, що завгодно, всередині анонімної функції.


4

Мені дуже сподобалося пояснення Маврія (найвища відповідь) трьома різними методами виклику setTimeout.

У своєму коді я хочу автоматично перейти на попередню сторінку після завершення події збереження AJAX. Завершення події збереження містить незначну анімацію в CSS, що свідчить про те, що збереження було успішним.

У своєму коді я знайшов різницю між першими двома прикладами:

setTimeout(window.history.back(), 3000);

Цей не чекає тайм-ауту - назад () викликається майже одразу, незалежно від того, яке число я вставлю для затримки.

Однак, змінивши це на:

setTimeout(function() {window.history.back()}, 3000);

Це робить саме те, на що я сподівався.

Це не характерно для операції back (), те ж саме відбувається і з операцією alert(). В основному при alert()використанні в першому випадку час затримки ігнорується. Коли я відхиляю спливаюче вікно, анімація для CSS продовжується.

Таким чином, я б рекомендував другий чи третій метод, який він описує, навіть якщо ви використовуєте вбудовані функції та не використовуєте аргументи.


1

У мене були кілька команд ajax, які я хотів запустити із затримкою між ними. Ось простий приклад одного із способів зробити це. Я готовий бути зірваним на клаптики, хоча за свій нетрадиційний підхід. :)

//  Show current seconds and milliseconds
//  (I know there are other ways, I was aiming for minimal code
//  and fixed width.)
function secs()
{
    var s = Date.now() + ""; s = s.substr(s.length - 5);
  return s.substr(0, 2) + "." + s.substr(2);
}

//  Log we're loading
console.log("Loading: " + secs());

//  Create a list of commands to execute
var cmds = 
[
    function() { console.log("A: " + secs()); },
    function() { console.log("B: " + secs()); },
    function() { console.log("C: " + secs()); },
    function() { console.log("D: " + secs()); },
    function() { console.log("E: " + secs()); },
  function() { console.log("done: " + secs()); }
];

//  Run each command with a second delay in between
var ms = 1000;
cmds.forEach(function(cmd, i)
{
    setTimeout(cmd, ms * i);
});

// Log we've loaded (probably logged before first command)
console.log("Loaded: " + secs());

Ви можете скопіювати блок коду та вставити його у вікно консолі та побачити щось на зразок:

Loading: 03.077
Loaded: 03.078
A: 03.079
B: 04.075
C: 05.075
D: 06.075
E: 07.076
done: 08.076

1

Найпростіше рішення викликати свою функцію із затримкою:

function executeWithDelay(anotherFunction) {
    setTimeout(anotherFunction, delayInMilliseconds);
}

0

функція затримки:

/**
 * delay or pause for some time
 * @param {number} t - time (ms)
 * @return {Promise<*>}
 */
const delay = async t => new Promise(resolve => setTimeout(resolve, t));

використання внутрішньої asyncфункції:

await delay(1000);

-1

Як інакше сказано, setTimeout - це ваша найбезпечніша ставка.
Але іноді ви не можете розділити логіку на нову функцію, тоді ви можете скористатися Date.now (), щоб отримати мілісекунди і зробити затримку самостійно ....

function delay(milisecondDelay) {
   milisecondDelay += Date.now();
   while(Date.now() < milisecondDelay){}
}

alert('Ill be back in 5 sec after you click OK....');
delay(5000);
alert('# Im back # date:' +new Date());

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.