gpt4 book ai didi

javascript - 如何创建自己的 setTimeout 函数?

转载 作者:行者123 更新时间:2023-11-30 07:31:38 25 4
gpt4 key购买 nike

我了解如何使用 setTimeout 函数,但我找不到创建类似函数的方法。
我有一个例子:

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

结果是 setTimeout 回调永远不会调用所以我认为它像每个 js 其他函数一样使用相同的线程。但是什么时候检查时间是否到达?以及它如何做到这一点?

已更新

为了避免误解,我更新了我的问题。
我找不到在指定时间后创建带回调的异步函数的方法(不使用 setTimeout 并且不阻塞整个线程)。这个函数 setTimeout 对我来说就像一个奇迹。我想了解它是如何工作的。

最佳答案

只是为了游戏,因为我真的不明白为什么你不能使用 setTimeout...


要创建一个非阻塞计时器,而不使用 setTimeout/setInterval 方法,您只有两种方法:

  • 基于事件的计时器
  • 在第二个线程中运行你的无限循环

基于事件的计时器

一个天真的实现是使用 MessageEvent接口(interface)和轮询,直到时间已到。但这对于长时间超时来说并不是真正的建议,因为这会迫使事件循环不断轮询新任务,这对树不利。

function myTimer(cb, ms) {
const begin = performance.now();
const channel = myTimer.channel ??= new MessageChannel();
const controller = new AbortController();
channel.port1.addEventListener("message", (evt) => {
if(performance.now() - begin >= ms) {
controller.abort();
cb();
}
else if(evt.data === begin) channel.port2.postMessage(begin);
}, { signal: controller.signal });
channel.port1.start();
channel.port2.postMessage(begin);
}

myTimer(() => console.log("world"), 2000);
myTimer(() => console.log("hello"), 100);

因此,如果可用的话,人们可能想使用 Web Audio APIAudioScheduledSourceNode ,它充分利用了高精度音频上下文自身的时钟:

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);

不同线程上的无限循环

是的,使用 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>

对于那些喜欢炫耀他们知道尚未真正可用的最新功能的人(完全不是我的风格),稍微提一下即将到来的 Prioritized Post Task API 及其 delayed tasks ,这基本上是一个更强大的 setTimeout,返回一个 promise ,我们可以在上面设置优先级。

(async () => {
if(globalThis.scheduler) {
const p1 = scheduler.postTask(()=>{ console.log("world"); }, { delay: 2000} );
const p2 = scheduler.postTask(()=>{ console.log("hello"); }, { delay: 1000} );
await p2;
console.log("future");
}
else {
console.log("Your browser doesn't support this API yet");
}
})();

关于javascript - 如何创建自己的 setTimeout 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50501356/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com