我了解如何使用setTimeout
功能,但我无法找到创建类似功能的方法。
我有一个例子:
setTimeout(() => {
console.log('3s');
}, 3000);
while(1);
结果是setTimeout
回调从不调用,所以我认为它使用与每个js其他函数相同的线程。但是当它检查时间到达时?以及它如何做到这一点?
为避免误会,我更新了我的问题
在指定时间后,我找不到使用回调创建异步函数的方法(不使用setTimeout
并且不阻止整个线程)。这个函数setTimeout
对我来说就像一个奇迹。我想了解它是如何工作的。
答案 0 :(得分:4)
没有调用setTimeout()回调的原因是,代码中有while(1)
,它充当无限循环。它将使你的javascript堆栈保持整个时间,这就是事件循环永远不会在堆栈中推送setTimeout()
的回调函数的原因。
如果从代码中删除while(1)
,则应调用setTimeout()
的回调。
setTimeout(() => {
console.log('3s');
}, 3000);
答案 1 :(得分:3)
因为我真的不知道为什么你不能使用setTimeout ......
要创建非阻塞计时器而不使用setTimeout / setInterval方法,您只有两种方法:
一个简单的实现是使用MessageEvent接口并轮询直到达到时间。但是,对于长时间超时而言,这并不是真正的建议......
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);

相反,如果可用,可能需要使用Web Audio API和AudioScheduledSourceNode,这可以充分利用高精度音频上下文自己的时钟:
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>
&#13;
答案 2 :(得分:0)
您好,可以尝试一下。 ] 它会有所帮助。谢谢
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);
答案 3 :(得分:0)
要创建自己的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());
答案 4 :(得分:0)
以下是自定义setTimeout和setInterval,clearTimeout和clearInterval的实现。我创建了它们以在内置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;
}
}