简体   繁体   English

如何创建自己的setTimeout函数?

[英]How to create your own setTimeout function?

I understand how to use setTimeout function, but I can't find a way to create a function like it. 我了解如何使用setTimeout函数,但是找不到找到类似函数的方法。
I have an example: 我有一个例子:

setTimeout(() => {
  console.log('3s');
}, 3000);
while(1);

The result is setTimeout callback never call so I think it use the same thread like every js other functions. 结果是setTimeout回调从不调用,所以我认为它像每个其他js函数一样使用相同的线程。 But when it's check the time reach or not? 但是,检查时间是否到了? and how it can do that? 以及如何做到这一点?

Updated 更新

To avoid misunderstanding I update my question. 为了避免造成误解,我更新了我的问题。
I can't find a way to create a async function with callback after specify time (without using setTimeout and don't block entire thread). 我找不到一种在指定时间后创建带有回调的异步函数的方法(不使用setTimeout且不阻塞整个线程)。 This function setTimeout seen like a miracle to me. setTimeout这个功能对我来说就像一个奇迹。 I want to understand how it work. 我想了解它是如何工作的。

The reason callback of setTimeout() is not being called is, you have while(1) in your code which acts as infinite loop. setTimeout()的回调未得到调用的原因是,您的代码中有while(1)作为无限循环。 It will keep your javascript stack busy whole time and that is the reason event loop will never push callback function of setTimeout() in stack. 这将使您的JavaScript堆栈一直处于忙碌状态,这就是事件循环从不将setTimeout()回调函数压入堆栈的原因。

If you remove while(1) from your code, callback for setTimeout() should get invoked. 如果从代码中删除while(1) ,则应调用setTimeout()回调。

 setTimeout(() => { console.log('3s'); }, 3000); 

Just for the game since I really don't see why you couldn't use setTimeout... 只是为了游戏,因为我真的不明白为什么不能使用setTimeout ...


To create a non-blocking timer, without using the setTimeout/setInterval methods, you have only two ways: 要创建一个非阻塞计时器而不使用setTimeout / setInterval方法,您只有两种方法:

  • event based timer 基于事件的计时器
  • run your infinite loop in a second thread 在第二个线程中运行无限循环

Event based timer 基于事件的计时器

One naive implementation would be to use the MessageEvent interface and polling until the time has been reached. 一种简单的实现是使用MessageEvent接口并轮询直到时间到为止。 But that's not really advice-able for long timeouts... 但这对于长时间的超时并不是真正的建议-

 function myTimer(cb, ms) { var now = performance.now(); window.addEventListener('message', handleMessage); postMessage('myTimer', '*'); function handleMessage(evt) { if(evt.data === 'myTimer') { if(performance.now() - now >= ms) { window.removeEventListener('message', handleMessage); cb(); } else { postMessage('myTimer', '*'); } } } } myTimer(()=>console.log('world'), 2000); myTimer(()=>console.log('hello'), 200); 

So instead, if available, one might want to use the Web Audio API and the AudioScheduledSourceNode , which makes great use of the high precision Audio Context's own clock: 因此,如果有的话,可能要使用Web Audio APIAudioScheduledSourceNode ,它们充分利用了高精度Audio Context自己的时钟:

 function myTimer(cb, ms) { if(!myTimer.ctx) myTimer.ctx = new (window.AudioContext || window.webkitAudioContext)(); var ctx = myTimer.ctx; var silence = ctx.createGain(); silence.gain.value = 0; var note = ctx.createOscillator(); note.connect(silence); silence.connect(ctx.destination); note.onended = function() { cb() }; note.start(0); note.stop(ctx.currentTime + (ms / 1000)); } myTimer(()=>console.log('world'), 2000); myTimer(()=>console.log('hello'), 200); 

Infinite loop on a different thread 不同线程上的无限循环

Yes, using Web Workers we can run infinite loops without killing our web page: 是的,使用Web Workers,我们可以运行无限循环而不会杀死我们的网页:

 function myTimer(cb, ms) { var workerBlob = new Blob([mytimerworkerscript.textContent], {type: 'application/javascript'}); var url = URL.createObjectURL(workerBlob); var worker = new Worker(url); worker.onmessage = function() { URL.revokeObjectURL(url); worker.terminate(); cb(); }; worker.postMessage(ms); } myTimer(()=>console.log('world'), 2000); myTimer(()=>console.log('hello'), 200); 
 <script id="mytimerworkerscript" type="application/worker-script"> self.onmessage = function(evt) { var ms = evt.data; var now = performance.now(); while(performance.now() - now < ms) {} self.postMessage('done'); } </script> 

Hi you can try this. 嗨,您可以尝试一下。 ] HOpe it will help. 希望它会有所帮助。 Thanks 谢谢

 function customSetTimeOut (callback, ms) { var dt = new Date(); var i = dt.getTime(); var future = i + ms; while(Date.now() <= future) { //do nothing - blocking } return callback(); } customSetTimeOut(function(){ console.log("Timeout success"); },1000); 

To create your own setTimeout function, you can use the following function, setMyTimeout() to do that without using setTimeout. 要创建自己的setTimeout函数,可以使用以下函数setMyTimeout()来执行此操作,而无需使用setTimeout。

 var foo= ()=>{ console.log(3,"Called after 3 seconds",new Date().getTime()); } var setMyTimeOut = (foo,timeOut)=>{ let timer; let currentTime = new Date().getTime(); let blah=()=>{ if (new Date().getTime() >= currentTime + timeOut) { clearInterval(timer); foo() } } timer= setInterval(blah, 100); } console.log(1,new Date().getTime()); setMyTimeOut(foo,3000) console.log(2,new Date().getTime()); 

Following is the implementation of custom setTimeout and setInterval, clearTimeout and clearInterval. 以下是自定义setTimeout和setInterval,clearTimeout和clearInterval的实现。 I created them to use in sandbox environments where builtin setTimeout and setInterval doesn't work. 我创建了它们以在内置setTimeout和setInterval不起作用的沙盒环境中使用。

const setTimeouts = [];
export function customSetTimeout(cb, interval) {
  const now = window.performance.now();
  const index = setTimeouts.length;
  setTimeouts[index] = () => {
    cb();
  };
  setTimeouts[index].active = true;
  const handleMessage = (evt) => {
    if (evt.data === index) {
      if (window.performance.now() - now >= interval) {
        window.removeEventListener('message', handleMessage);
        if (setTimeouts[index].active) {
          setTimeouts[index]();
        }
      } else {
        window.postMessage(index, '*');
      }
    }
  };
  window.addEventListener('message', handleMessage);
  window.postMessage(index, '*');
  return index;
}

export function customClearTimeout(setTimeoutId) {
  if (setTimeouts[setTimeoutId]) {
    setTimeouts[setTimeoutId].active = false;
  }
}

const setIntervals = [];
export function customSetInterval(cb, interval) {
  const intervalId = setIntervals.length;
  setIntervals[intervalId] = function () {
    if (setIntervals[intervalId].active) {
      cb();
      customSetTimeout(setIntervals[intervalId], interval);
    }
  };
  setIntervals[intervalId].active = true;
  customSetTimeout(setIntervals[intervalId], interval);
  return intervalId;
}

export function customClearInterval(intervalId) {
  if (setIntervals[intervalId]) {
    setIntervals[intervalId].active = false;
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM