Синхронная задержка при выполнении кода

У меня есть код, который нужно выполнить после некоторой задержки сказать 5000 м. В настоящее время я использую setTimeout, но он асинхронный, и я хочу, чтобы выполнение ожидало его возвращения. Я попытался использовать следующее:

function pauseComp(ms) 
 {
     var curr = new Date().getTime();
     ms += curr;
     while (curr   < ms) {
         curr = new Date().getTime();
     }
 } 

Но код, который я хочу отложить, - это рисование некоторых объектов с помощью raphaeljs, и отображение совсем не плавное. Я пытаюсь использовать плагин doTimeout. Мне нужно иметь задержку только один раз, так как задержка и код, который должен быть задержан, находятся в цикле. У меня нет требования для идентификатора, поэтому я его не использую. Например:

for(i; i<5; i++){ $.doTimeout(5000,function(){
         alert('hi');  return false;}, true);}

Это ждет 5 секунд для подачи первого приветствия, а затем последовательные итерации цикла показывают предупреждение сразу после первого. То, что я хочу, это подождать 5 секунд, чтобы снова предупредить, а затем дать предупреждение и так далее.

Любые подсказки/предложения оценены!

Ответы

Ответ 1

Изменение принятого ответа, которое так же хорошо, как и этот.

Кроме того, я согласен с предостережениями о предпочтении setTimeout и вызова асинхронной функции, но иногда, например, при создании тестов вам просто нужна команда синхронного ожидания...

function wait(ms) {
    var start = Date.now(),
        now = start;
    while (now - start < ms) {
      now = Date.now();
    }
}

если вы хотите его в секундах, делите начальный миллион на 1000 при проверке...

Ответ 2

Если вы хотите воспользоваться новым синтаксисом async/await, вы можете преобразовать установленное время ожидания в обещание, а затем ожидать его.

function wait(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("Done waiting");
      resolve(ms)
    }, ms )
  })
}  

(async function Main() {
  console.log("Starting...")
  await wait(5000);
  console.log("Ended!")
})();

Ответ 3

JavaScript - это однопоточный язык. Вы не можете объединить setTimeout и синхронную обработку. Что произойдет, таймер закроется, но тогда механизм JS будет ждать обработки результатов до тех пор, пока не завершится текущий script.

Если вы хотите синхронные методы, просто вызовите метод напрямую!

Если вы хотите обработать что-то после setTimeout, включите его или вызовите его из функции тайм-аута.

Ответ 4

Циклы без тайм-аута (которые проверяют время или число до 1000000 или что-то еще) просто блокируют браузер. setTimeout (или плагин $.doTimeout) - лучший способ сделать это.

Создание тайм-аутов в цикле не будет работать, потому что цикл не ожидает появления предыдущего таймаута, прежде чем продолжить, как вы это обнаружили. Попробуйте еще что-нибудь подобное:

// Generic function to execute a callback a given number
// of times with a given delay between each execution
function timeoutLoop(fn, reps, delay) {
  if (reps > 0)
    setTimeout(function() {
                 fn();
                 timeoutLoop(fn, reps-1, delay);
               }, delay);
}

// pass your function as callback
timeoutLoop(function() { alert("Hi"); },
            5,
            5000);

(Я просто быстро вымотал это вместе, поэтому, хотя я уверен, что он работает, его можно улучшить несколькими способами, например, в "цикле" он может передать значение индекса в функцию обратного вызова, чтобы ваш собственный код знает, к какой итерации это нужно. Но, надеюсь, это поможет вам начать.)

Ответ 5

Я сделал простую синхронную функцию таймаута. Он работает по-разному: обратный вызов и обратный вызов.

функция:

function wait(ms, cb) {
  var waitDateOne = new Date();
  while ((new Date()) - waitDateOne <= ms) {
    //Nothing
  }
  if (cb) {
    eval(cb);
  }
}

Пример обратного вызова:

wait(5000,"doSomething();");

пример без обратного вызова:

console.log("Instant!");
wait(5000);
console.log("5 second delay");

Ответ 6

Здесь вы можете использовать плагин JQuery doTimeout

jQuery('selector').doTimeout( [ id, ] delay, callback [, arg ... ] );

Из docs: "Если обратный вызов возвращает true, цикл doTimeout будет выполняться снова, после задержки, создавая цикл опроса, пока обратный вызов не возвращает неверное значение".

var start = Date.now();
console.log("start: ", Date.now() - start);
var i = 0;
$.doTimeout('myLoop', 5000, function() {
  console.log(i+1, Date.now() - start);
  ++i;
  return i == 5 ? false : true;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-dotimeout/1.0/jquery.ba-dotimeout.min.js"></script>

Ответ 7

Синхронное ожидание (только для тестирования!):

const syncWait = ms => {
    const end = Date.now() + ms
    while (Date.now() < end) continue
}

Асинхронное ожидание:

const asyncWait = ms => new Promise(resolve => setTimeout(resolve, ms))

Вызовите массив функций с задержками между вызовами:

const delayedForEach = (array, ms) =>
    array.forEach((func, index) => setTimeout(func, index * ms))

Использование:

delayedForEach([
    () => console.log('one'),
    () => console.log('two'),
    () => console.log('three'),
], 5000)

Ответ 8

Решение с использованием генераторов функций. Чтобы показать, что это можно сделать. Не рекомендуется.

function wait(miliseconds){

  const gen = function * (){
     const end = Date.now() + miliseconds;
     while(Date.now() < end){yield};
     return;
  }
  
  const iter = gen();
  while(iter.next().done === false);
}


console.log("done 0");
wait(1000);
console.log("done 1");
wait(2000);
console.log("done 2");