Я пишу некоторый Javascript, который взаимодействует с кодом библиотеки, которым я не владею, и не могу (разумно) изменить. Он создает тайм-ауты Javascript, используемые для отображения следующего вопроса в серии ограниченных по времени вопросов. Это не настоящий код, потому что он безнадежно запутан. Вот что делает библиотека:
....
// setup a timeout to go to the next question based on user-supplied time
var t = questionTime * 1000
test.currentTimeout = setTimeout( showNextQuestion(questions[i+1]), t );
Я хочу разместить на экране индикатор выполнения, который заполняется questionTime * 1000
, запрашивая таймер, созданный setTimeout
. Единственная проблема в том, что, похоже, это невозможно сделать. Есть ли getTimeout
функция, которую мне не хватает? Единственная информация о тайм-аутах Javascript, которую я могу найти, связана только с созданием черезsetTimeout( function, time)
и удалением через clearTimeout( id )
.
Я ищу функцию, которая возвращает либо время, оставшееся до срабатывания тайм-аута, либо время, прошедшее после того, как тайм-аут был вызван. Мой штрих-код выполнения выглядит так:
var timeleft = getTimeout( test.currentTimeout ); // I don't know how to do this
var $bar = $('.control .bar');
while ( timeleft > 1 ) {
$bar.width(timeleft / test.defaultQuestionTime * 1000);
}
tl; dr: Как мне узнать время, оставшееся до javascript setTimeout ()?
Вот решение, которое я использую сейчас. Я прошел через раздел библиотеки, который отвечает за тесты, и расшифровал код (ужасно и против моих разрешений).
// setup a timeout to go to the next question based on user-supplied time
var t = questionTime * 1000
test.currentTimeout = mySetTimeout( showNextQuestion(questions[i+1]), t );
а вот мой код:
// оболочка для setTimeout function mySetTimeout (func, timeout) { таймауты [n = setTimeout (func, timeout)] = { начало: новая дата (). getTime (), конец: новая дата (). getTime () + тайм-аут t: тайм-аут } return n; }
Это прекрасно работает в любом браузере, кроме IE 6. Даже в оригинальном iPhone, где я ожидал, что все будет асинхронным.
источник
Для записи, есть способ узнать оставшееся время в node.js:
var timeout = setTimeout(function() {}, 3600 * 1000); setInterval(function() { console.log('Time left: '+getTimeLeft(timeout)+'s'); }, 2000); function getTimeLeft(timeout) { return Math.ceil((timeout._idleStart + timeout._idleTimeout - Date.now()) / 1000); }
Печать:
Похоже, это не работает в firefox, но поскольку node.js - это javascript, я подумал, что это замечание может быть полезно для людей, которые ищут решение node.
источник
getTime()
удалено,_idleStart
уже времяРЕДАКТИРОВАТЬ: Я действительно думаю, что сделал еще лучше: https://stackoverflow.com/a/36389263/2378102
Я написал эту функцию и много ею пользуюсь:
function timer(callback, delay) { var id, started, remaining = delay, running this.start = function() { running = true started = new Date() id = setTimeout(callback, remaining) } this.pause = function() { running = false clearTimeout(id) remaining -= new Date() - started } this.getTimeLeft = function() { if (running) { this.pause() this.start() } return remaining } this.getStateRunning = function() { return running } this.start() }
Сделайте таймер:
a = new timer(function() { // What ever }, 3000)
Итак, если вы хотите, чтобы оставшееся время просто:
источник
Стеки событий Javascript работают не так, как вы думаете.
Когда создается событие тайм-аута, оно добавляется в очередь событий, но другие события могут иметь приоритет, пока это событие запускается, задерживая время выполнения и откладывая время выполнения.
Пример: вы создаете тайм-аут с задержкой в 10 секунд, чтобы что-то предупредить на экране. Он будет добавлен в стек событий и будет выполняться после запуска всех текущих событий (вызывая некоторую задержку). Затем, когда истечет время ожидания, браузер по-прежнему будет перехватывать другие события, добавляя их в стек, что вызывает дополнительные задержки в обработке. Если пользователь щелкает или много набирает Ctrl +, их события имеют приоритет над текущим стеком. Ваши 10 секунд могут превратиться в 15 секунд или больше.
При этом есть много способов подделать, сколько времени прошло. Один из способов - выполнить setInterval сразу после добавления setTimeout в стек.
Пример: Выполните установку тайм-аута с 10-секундной задержкой (сохраните эту задержку в глобальном). Затем выполните setInterval, который запускается каждую секунду, чтобы вычесть 1 из задержки и вывести оставшуюся задержку. Из-за того, как стек событий может влиять на фактическое время (описано выше), это все равно не будет точным, но дает счет.
Короче говоря, реального способа получить оставшееся время нет. Есть только способы попытаться донести оценку до пользователя.
источник
Специфично для Node.js на стороне сервера
Ничего из вышеперечисленного на самом деле не сработало для меня, и после проверки объекта тайм-аута все выглядело так, как будто все было относительно того, когда процесс начался. Для меня сработало следующее:
myTimer = setTimeout(function a(){console.log('Timer executed')},15000); function getTimeLeft(timeout){ console.log(Math.ceil((timeout._idleStart + timeout._idleTimeout)/1000 - process.uptime())); } setInterval(getTimeLeft,1000,myTimer);
Вывод:
14 ... 3 2 1 Timer executed -0 -1 ... node -v v9.11.1
Отредактированный вывод для краткости, но эта базовая функция дает приблизительное время до выполнения или с момента выполнения. Как отмечают другие, ничто из этого не будет точным из-за того, как обрабатывается узел, но если я хочу подавить запрос, который был запущен менее 1 минуты назад, и я сохранил таймер, я не понимаю, почему это не работать как быстрая проверка. Может быть интересно жонглировать объектами с помощью таймера в 10.2+.
источник
Вы можете изменить
setTimeout
время окончания каждого тайм-аута на карте и создать функцию, вызываемуюgetTimeout
для получения времени, оставшегося до тайм-аута с определенным идентификатором.Это было супер «s решение , но я изменил его , чтобы использовать немного меньше памяти
let getTimeout = (() => { // IIFE let _setTimeout = setTimeout, // Reference to the original setTimeout map = {}; // Map of all timeouts with their end times setTimeout = (callback, delay) => { // Modify setTimeout let id = _setTimeout(callback, delay); // Run the original, and store the id map[id] = Date.now() + delay; // Store the end time return id; // Return the id }; return (id) => { // The actual getTimeout function // If there was no timeout with that id, return NaN, otherwise, return the time left clamped to 0 return map[id] ? Math.max(map[id] - Date.now(), 0) : NaN; } })();
Применение:
// go home in 4 seconds let redirectTimeout = setTimeout(() => { window.location.href = "/index.html"; }, 4000); // display the time left until the redirect setInterval(() => { document.querySelector("#countdown").innerHTML = `Time left until redirect ${getTimeout(redirectTimeout)}`; },1);
Вот уменьшенная версия этого
getTimeout
IIFE :let getTimeout=(()=>{let t=setTimeout,e={};return setTimeout=((a,o)=>{let u=t(a,o);return e[u]=Date.now()+o,u}),t=>e[t]?Math.max(e[t]-Date.now(),0):NaN})();
Надеюсь, это будет так же полезно для вас, как и для меня! :)
источник
Нет, но у вас может быть собственный setTimeout / setInterval для анимации в вашей функции.
Допустим, ваш вопрос выглядит так:
function myQuestion() { // animate the progress bar for 1 sec animate( "progressbar", 1000 ); // do the question stuff // ... }
И ваша анимация будет обрабатываться этими двумя функциями:
function interpolate( start, end, pos ) { return start + ( pos * (end - start) ); } function animate( dom, interval, delay ) { interval = interval || 1000; delay = delay || 10; var start = Number(new Date()); if ( typeof dom === "string" ) { dom = document.getElementById( dom ); } function step() { var now = Number(new Date()), elapsed = now - start, pos = elapsed / interval, value = ~~interpolate( 0, 500, pos ); // 0-500px (progress bar) dom.style.width = value + "px"; if ( elapsed < interval ) setTimeout( step, delay ); } setTimeout( step, delay ); }
источник
Если кто-то оглядывается на это. Я выпустил диспетчер тайм-аута и интервалов, который может дать вам время, оставшееся до тайм-аута или интервала, а также сделать некоторые другие вещи. Я добавлю к нему, чтобы сделать его более изящным и точным, но, похоже, он и так работает достаточно хорошо (хотя у меня есть еще несколько идей, чтобы сделать его еще более точным):
https://github.com/vhmth/Tock
источник
На вопрос уже был дан ответ, но я добавлю свой бит. Это просто произошло со мной.
Используйте
setTimeout
вrecursion
следующих случаях:var count = -1; function beginTimer() { console.log("Counting 20 seconds"); count++; if(count <20) { console.log(20-count+"seconds left"); setTimeout(beginTimer,2000); } else { endTimer(); } } function endTimer() { console.log("Time is finished"); }
Я думаю, код не требует пояснений
источник
Отметьте это:
class Timer { constructor(fun,delay) { this.timer=setTimeout(fun, delay) this.stamp=new Date() } get(){return ((this.timer._idleTimeout - (new Date-this.stamp))/1000) } clear(){return (this.stamp=null, clearTimeout(this.timer))} }
Сделайте таймер:
let smtg = new Timer(()=>{do()}, 3000})
Получить остаток:
Очистить тайм-аут
источник
(function(){ window.activeCountdowns = []; window.setCountdown = function (code, delay, callback, interval) { var timeout = delay; var timeoutId = setTimeout(function(){ clearCountdown(timeoutId); return code(); }, delay); window.activeCountdowns.push(timeoutId); setTimeout(function countdown(){ var key = window.activeCountdowns.indexOf(timeoutId); if (key < 0) return; timeout -= interval; setTimeout(countdown, interval); return callback(timeout); }, interval); return timeoutId; }; window.clearCountdown = function (timeoutId) { clearTimeout(timeoutId); var key = window.activeCountdowns.indexOf(timeoutId); if (key < 0) return; window.activeCountdowns.splice(key, 1); }; })(); //example var t = setCountdown(function () { console.log('done'); }, 15000, function (i) { console.log(i / 1000); }, 1000);
источник
Я остановился здесь в поисках этого ответа, но слишком много думал о своей проблеме. Если вы здесь, потому что вам просто нужно отслеживать время, пока выполняется setTimeout, вот еще один способ сделать это:
var focusTime = parseInt(msg.time) * 1000 setTimeout(function() { alert('Nice Job Heres 5 Schrute bucks') clearInterval(timerInterval) }, focusTime) var timerInterval = setInterval(function(){ focusTime -= 1000 initTimer(focusTime / 1000) }, 1000);
источник
Более быстрый и простой способ:
tmo = 1000; start = performance.now(); setTimeout(function(){ foo(); },tmo);
Вы можете узнать оставшееся время с помощью:
источник