Javascript 在setTimeout()中查找剩余时间?

Javascript 在setTimeout()中查找剩余时间?,javascript,timeout,settimeout,Javascript,Timeout,Settimeout,我正在编写一些Javascript,这些Javascript与我不拥有的库代码交互,并且不能(合理地)更改。它创建Javascript超时,用于显示一系列限时问题中的下一个问题。这不是真正的代码,因为它被混淆了。以下是图书馆正在做的事情: .... // setup a timeout to go to the next question based on user-supplied time var t = questionTime * 1000 test.currentTimeout = s

我正在编写一些Javascript,这些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 );
我想通过询问由
setTimeout
创建的计时器,在屏幕上显示一个进度条,该进度条将填满
questionTime*1000
。唯一的问题是,似乎没有办法做到这一点。是否有我缺少的
getTimeout
函数?我能找到的关于Javascript超时的唯一信息仅与通过
setTimeout(函数,时间)
创建和通过
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);
}
function myQuestion() {
  // animate the progress bar for 1 sec
  animate( "progressbar", 1000 );

  // do the question stuff
  // ...
}
tl;dr:如何找到javascript setTimeout()之前的剩余时间?


这是我现在使用的解决方案。我浏览了负责测试的库部分,并对代码进行了解读(很糟糕,而且违反了我的权限)

这是我的代码:

// wrapper for setTimeout function mySetTimeout( func, timeout ) { timeouts[ n = setTimeout( func, timeout ) ] = { start: new Date().getTime(), end: new Date().getTime() + timeout t: timeout } return n; } //setTimeout的包装器 函数mySetTimeout(函数,超时){ 超时[n=设置超时(函数,超时)]={ 开始:新日期().getTime(), 结束:新日期().getTime()+超时 t:超时 } 返回n; }
这在任何不是IE6的浏览器中都非常有效。即使是最初的iPhone,在那里我希望事情变得异步。

不,但是您可以在函数中为动画设置自己的setTimeout/setInterval

假设你的问题是这样的:

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);
}
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 );
}
函数插值(开始、结束、位置){
返回开始+(位置*(结束-开始));
}
函数动画(dom、间隔、延迟){
间隔=间隔| | 1000;
延迟=延迟| | 10;
var start=Number(新日期());
如果(dom的类型==“字符串”){
dom=document.getElementById(dom);
}
函数步骤(){
var now=编号(新日期()),
已用=现在-开始,
pos=经过时间/间隔,
值=~~插值(0500,位置);//0-500px(进度条)
dom.style.width=值+px;
如果(经过<间隔)
设置超时(步进,延迟);
}
设置超时(步进,延迟);
}

Javascript的事件堆栈不会按照您的想法进行操作

创建超时事件时,会将其添加到事件队列中,但在触发该事件时,其他事件可能具有优先级,延迟执行时间并延迟运行时

示例:您创建了一个延迟10秒的超时,以向屏幕发出警报。它将被添加到事件堆栈中,并将在触发所有当前事件后执行(导致一些延迟)。然后,在处理超时时,浏览器仍会继续捕获其他事件并将其添加到堆栈中,这会导致处理过程中的进一步延迟。如果用户单击,或大量按ctrl+键,则其事件优先于当前堆栈。你的10秒可以变成15秒,甚至更长


也就是说,有很多方法可以假装时间流逝了多少。一种方法是在将setTimeout添加到堆栈后立即执行setInterval

示例:以10秒的延迟执行设置超时(将该延迟存储在全局设置中)。然后执行每秒运行一次的setInterval,从延迟中减去1,并输出剩余的延迟。由于事件堆栈如何影响实际时间(如上所述),这仍然不准确,但会给出一个计数



简而言之,没有真正的方法来获得剩余的时间。只有几种方法可以尝试向用户传达估算值。

如果无法修改库代码,则需要重新定义setTimeout以满足您的目的。下面是一个您可以做的示例:

(function () {
var nativeSetTimeout = window.setTimeout;

window.bindTimeout = function (listener, interval) {
    function setTimeout(code, delay) {
        var elapsed = 0,
            h;

        h = window.setInterval(function () {
                elapsed += interval;
                if (elapsed < delay) {
                    listener(delay - elapsed);
                } else {
                    window.clearInterval(h);
                }
            }, interval);
        return nativeSetTimeout(code, delay);
    }

    window.setTimeout = setTimeout;
    setTimeout._native = nativeSetTimeout;
};
}());
window.bindTimeout(function (t) {console.log(t + "ms remaining");}, 100);
window.setTimeout(function () {console.log("All done.");}, 1000);
(函数(){
var nativeSetTimeout=window.setTimeout;
window.bindTimeout=函数(侦听器,间隔){
函数设置超时(代码、延迟){
var=0,
H
h=窗口.setInterval(函数(){
经过时间+=间隔;
如果(经过<延迟){
侦听器(延迟-已用);
}否则{
窗口。清除间隔(h);
}
},间隔);
返回nativeSetTimeout(代码,延迟);
}
window.setTimeout=setTimeout;
设置超时。_native=nativeSetTimeout;
};
}());
bindTimeout(函数(t){console.log(t+“ms剩余”);},100);
setTimeout(函数(){console.log(“全部完成”);},1000);
这不是生产代码,但它应该让您走上正确的轨道。请注意,每次超时只能绑定一个侦听器。我还没有用这个做过广泛的测试,但它在Firebug中工作


更健壮的解决方案将使用包装setTimeout的相同技术,但使用从返回的timeoutId到侦听器的映射来处理每个超时的多个侦听器。您也可以考虑包装清除超时,以便在超时被清除时可以分离您的侦听器。

对于记录,有一种方法可以获得在节点中留下的时间。js:< /p>
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);
}
印刷品:

$ node test.js 
Time left: 3599s
Time left: 3597s
Time left: 3595s
Time left: 3593s

这在firefox中似乎不起作用,但由于node.js是javascript,我认为这句话可能对寻找节点解决方案的人有所帮助。

如果有人回顾这一点的话。我已经推出了一个超时和间隔管理器,它可以让你在一个超时或间隔的时间,以及做一些其他事情。我将添加到它,使它更漂亮,更准确,但它似乎工作得相当好,因为是(虽然我有一些更多的想法,使它成为夏娃)
a = new timer(function() {
    // What ever
}, 3000)
a.getTimeLeft()
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})
smth.get()
smth.clear()
    (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);
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
    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);
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);
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})();
tmo = 1000;
start = performance.now();
setTimeout(function(){
    foo();
},tmo);
 timeLeft = tmo - (performance.now() - start);