【问题标题】:Force setTimeout to fire its payload earlier than originally set强制 setTimeout 比最初设置更早地触发其有效载荷
【发布时间】:2011-10-07 15:13:42
【问题描述】:

我开发了一小部分演示软件,其中包含幻灯片和每张幻灯片的资产。渲染幻灯片时,其所有资源都会循环播放,并在使用 setTimeout 方法延迟后渲染。看起来很甜……

耶!,要求已经改变,现在要求演示文稿像 PowerPoint 幻灯片一样,鼠标单击事件将导致下一个资源立即呈现到页面。

我的问题是;有没有办法让我的超时立即触发?我可以获取超时ID并将其存储在堆栈中,因为它是在创建超时时返回的。唯一的其他选择是取消超时,然后重新创建元素,这比我想做的处理要多得多,而且我不想过多地重构我的代码。

有什么想法吗?

【问题讨论】:

    标签: javascript jquery settimeout


    【解决方案1】:

    你可以像这样将它包裹在一个闭包中:

    function createTimeout(timeoutHandler, delay) {
        var timeoutId;
        timeoutId = setTimeout(timeoutHandler, delay);
        return {
            clear: function() {
                clearTimeout(timeoutId);
            },
            trigger: function() {
                clearTimeout(timeoutId);
                return timeoutHandler();
            }
        };
    }
    
    var a = new Date();
    
    var timeout = createTimeout(function() { console.log(a); }, 1000);
    // timeout.clear();
    timeout.trigger();
    

    更新(现代 js):

    let newTimeout = (handler, delay) => {
        let id = setTimeout(handler, delay), clear = clearTimeout.bind(null, id);
        return {id, clear, trigger: () => (clear(), handler())};
    };
    
    let timeout = newTimeout(() => console.log(new Date()), 1000);
    // timeout.clear();
    timeout.trigger();
    

    【讨论】:

    • 优雅的解决方案
    • 或者,更现代的:var createTimeout = (handler, delay) => { var id = setTimeout(handler, delay), clear = () => clearTimeout(id); return {clear, restart: (newDelay) => (clear(), (id = setTimeout(handler, newDelay || delay))), trigger: () => (clear(), handler())} };
    【解决方案2】:

    如果你这样设置定时器:

    var timer1 = window.setTimeout(mainFunction,500)
    

    立即调用它:

    window.clearTimeout(timer1)
    mainFunction()
    

    关键是把函数和定时器分开。

    【讨论】:

    • 便便,我想我必须这样做,我希望能快速解决。由于“mainFunction”在首次设置超时时计算了参数,因此我需要进行一些重构以使它们出现在 onlick 事件中......非常感谢
    • 请参阅下面的我的答案,以了解避免管理更多内容的闭包包装。将 timeoutId 替换为具有 .cancel() 和 .trigger() 方法的对象。
    【解决方案3】:

    简短的回答是不。 除非您保留要解雇的方法列表,否则您无法按照您的要求进行操作。然后你可以取消定时器并触发相应的方法。

    【讨论】:

      【解决方案4】:

      我刚刚遇到这个问题,并最终编写了一个便利类来处理这个问题(使用 es6,因此您需要对其进行转译以实现向后兼容性):

      class Animations {
        constructor() {
          this.queue = [];
          this.nextId = 0;
        }
        add(fn, delay) {
          let id = this.nextId++;
          let timeout = window.setTimeout(() => {
            this.queue = this.queue.filter(d => d.id !== id);
            fn();
          }, delay);
          this.queue.push({ id, fn, timeout });
          return id;
        }
        flush() {
          this.queue.forEach(d => {
            window.clearTimeout(d.timeout);
            d.fn();
          });
          this.queue = [];
        }
      }
      
      export default Animations;
      

      然后,我不使用 setTimeout,而是使用 Animations 类的一个实例来管理所有状态,并让我通过 .add(fn, delay) 方法设置超时,但我可以通过 .flush() 强制待处理的运行。

      import Animations from './animations';
      
      let anims = new Animations();
      
      anims.add(() => {
        someElt.classList.add('some-class');
      }, 1000);
      
      // then, whenever you want to force it execute immediately
      anims.flush();
      

      【讨论】:

      • 一个不错的解决方案:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多