清除各种间隔
Clear all kind of intervals
想象这样一种场景,您的主要功能执行 2 个开始间隔的功能。这些函数作为 NodeJS 模块导入并执行。然后在一段时间后在主函数中清除间隔。另请注意,我们将在未来的主要功能中有更多的间隔。
所以主要功能是
(() => {
const intervals = [];
intervals.push(require('./simpleInterval')());
intervals.push(require('./asyncInterval')());
setTimeout(() => {
intervals.forEach(id => clearInterval(id));
}, 1200)
})();
这些方法之一就是
const intervalFoo = () => {
return setInterval(() => {
console.log('interval simple')
}, 500);
};
module.exports = intervalFoo;
但是第二个包含一些异步代码,可以执行比间隔间隙更长的时间,但我不希望它在前一个 "iteration" 未完成之前开始。这种情况的解决方案是在开始时通过id清除间隔,然后在间隔的末尾(但在主体内)重新分配它。所以asyncInterval.js
的代码是:
const sleep = require('./utilities/sleep');
const intervalFoo = () => {
let intervalId;
const checkE2Interval = async() => {
clearInterval(intervalId);
console.log('interval async');
await sleep(120); //some long action
return intervalId = setInterval(checkE2Interval, 100);
};
return intervalId = setInterval(checkE2Interval, 100); //returning id
};
module.exports = intervalFoo;
(睡眠只是一个承诺,在作为参数给出的超时时间后解决)
关于这个的问题是我也在间隔期间从 asyncInterval.js
返回 intervalId
,我的问题是我不知道我应该如何清除这个东西。
提供取消函数而不是提供原始句柄,并向您的函数传递一个带有标志的对象,它可以检查它是否已被取消:
function mySetInterval(callback, ms, ...args) {
let token = {
cancelled: false
};
function wrapper(...args) {
callback(token, ...args);
if (!token.cancelled) {
id = setTimeout(wrapper, ms, ...args);
}
}
let id = setTimeout(wrapper, ms, ...args);
return function cancel() {
clearInterval(id);
token.cancelled = true;
}
}
因为0
是一个无效的计时器ID,我们可以安全地使用它作为间隔已被取消的标志。请注意,链式 setTimeout
(上图)和 setInterval
(setInterval
对间隔之间延迟的处理是.. .interesting.)另请注意,上面没有任何内容可以阻止函数在 sleep
暂停时被调用。要做到这一点,你必须有一个守卫,并让函数 特别是 支持异步函数:
function mySetInterval(callback, ms, ...args) {
let token = {
cancelled: false
};
let running = false;
async function wrapper(...args) {
if (!running) {
running = true;
await callback(token, ...args);
running = false;
}
if (!token.cancelled) {
id = setTimeout(wrapper, ms, ...args);
}
}
let id = setTimeout(wrapper, ms, ...args);
return function cancel() {
clearInterval(id);
token.cancelled = true;
}
}
使用该函数代替 setInterval
。
在你的异步函数中,如果它永远没有理由停止自己:
const intervalFoo = () => {
const checkE2Interval = async(token) => {
console.log('interval async');
await sleep(120); //some long action
// If you had more logic here, you could short-circuit it by checking token.cancelled
};
return mySetInterval(checkE2Interval, 100); //returning id
};
如果确实有理由停止自己,保存cancel
:
const intervalFoo = () => {
let cancel = null;
const checkE2Interval = async(token) => {
console.log('interval async');
await sleep(120); //some long action
// If you had more logic here, you could short-circuit it by checking token.cancelled
// If you wanted not to continue the timer, you'd call cancel here
};
return cancel = mySetInterval(checkE2Interval, 100); //returning id
};
那么,需要取消的地方:
(() => {
const cancellers = [];
cancellers.push(require('./simpleInterval')());
cancellers.push(require('./asyncInterval')());
setTimeout(() => {
cancellers.forEach(cancel => cancel());
}, 1200)
})();
实例:
const sleep = ms => new Promise(resolve => {
setTimeout(resolve, ms);
});
function mySetInterval(callback, ms, ...args) {
let token = {
cancelled: false
};
function wrapper(...args) {
callback(token, ...args);
if (!token.cancelled) {
id = setTimeout(wrapper, ms, ...args);
}
}
let id = setTimeout(wrapper, ms, ...args);
return function cancel() {
clearInterval(id);
token.cancelled = true;
}
}
const intervalFoo = () => {
let cancel = null;
const checkE2Interval = async(token) => {
console.log('interval async');
await sleep(120); //some long action
// If you had more logic here, you could short-circuit it by checking token.cancelled
// If you wanted not to continue the timer, you'd call cancel here
};
return cancel = mySetInterval(checkE2Interval, 100); //returning id
};
(() => {
const cancellers = [];
cancellers.push(intervalFoo());
setTimeout(() => {
console.log("Cancelling");
cancellers.forEach(cancel => {
cancel();
});
}, 1200)
})();
带有 running
标志的实例:
const sleep = ms => new Promise(resolve => {
setTimeout(resolve, ms);
});
function mySetInterval(callback, ms, ...args) {
let token = {
cancelled: false
};
let running = false;
async function wrapper(...args) {
if (!running) {
running = true;
await callback(token, ...args);
running = false;
}
if (!token.cancelled) {
id = setTimeout(wrapper, ms, ...args);
}
}
let id = setTimeout(wrapper, ms, ...args);
return function cancel() {
clearInterval(id);
token.cancelled = true;
}
}
const intervalFoo = () => {
let cancel = null;
const checkE2Interval = async(token) => {
console.log('interval async');
await sleep(120); //some long action
console.log('awake');
// If you had more logic here, you could short-circuit it by checking token.cancelled
// If you wanted not to continue the timer, you'd call cancel here
};
return cancel = mySetInterval(checkE2Interval, 100); //returning id
};
(() => {
const cancellers = [];
cancellers.push(intervalFoo());
setTimeout(() => {
console.log("Cancelling");
cancellers.forEach(cancel => {
cancel();
});
}, 1200)
})();
您可以进一步概括这一点,但您已经掌握了基本思想。
想象这样一种场景,您的主要功能执行 2 个开始间隔的功能。这些函数作为 NodeJS 模块导入并执行。然后在一段时间后在主函数中清除间隔。另请注意,我们将在未来的主要功能中有更多的间隔。
所以主要功能是
(() => {
const intervals = [];
intervals.push(require('./simpleInterval')());
intervals.push(require('./asyncInterval')());
setTimeout(() => {
intervals.forEach(id => clearInterval(id));
}, 1200)
})();
这些方法之一就是
const intervalFoo = () => {
return setInterval(() => {
console.log('interval simple')
}, 500);
};
module.exports = intervalFoo;
但是第二个包含一些异步代码,可以执行比间隔间隙更长的时间,但我不希望它在前一个 "iteration" 未完成之前开始。这种情况的解决方案是在开始时通过id清除间隔,然后在间隔的末尾(但在主体内)重新分配它。所以asyncInterval.js
的代码是:
const sleep = require('./utilities/sleep');
const intervalFoo = () => {
let intervalId;
const checkE2Interval = async() => {
clearInterval(intervalId);
console.log('interval async');
await sleep(120); //some long action
return intervalId = setInterval(checkE2Interval, 100);
};
return intervalId = setInterval(checkE2Interval, 100); //returning id
};
module.exports = intervalFoo;
(睡眠只是一个承诺,在作为参数给出的超时时间后解决)
关于这个的问题是我也在间隔期间从 asyncInterval.js
返回 intervalId
,我的问题是我不知道我应该如何清除这个东西。
提供取消函数而不是提供原始句柄,并向您的函数传递一个带有标志的对象,它可以检查它是否已被取消:
function mySetInterval(callback, ms, ...args) {
let token = {
cancelled: false
};
function wrapper(...args) {
callback(token, ...args);
if (!token.cancelled) {
id = setTimeout(wrapper, ms, ...args);
}
}
let id = setTimeout(wrapper, ms, ...args);
return function cancel() {
clearInterval(id);
token.cancelled = true;
}
}
因为0
是一个无效的计时器ID,我们可以安全地使用它作为间隔已被取消的标志。请注意,链式 setTimeout
(上图)和 setInterval
(setInterval
对间隔之间延迟的处理是.. .interesting.)另请注意,上面没有任何内容可以阻止函数在 sleep
暂停时被调用。要做到这一点,你必须有一个守卫,并让函数 特别是 支持异步函数:
function mySetInterval(callback, ms, ...args) {
let token = {
cancelled: false
};
let running = false;
async function wrapper(...args) {
if (!running) {
running = true;
await callback(token, ...args);
running = false;
}
if (!token.cancelled) {
id = setTimeout(wrapper, ms, ...args);
}
}
let id = setTimeout(wrapper, ms, ...args);
return function cancel() {
clearInterval(id);
token.cancelled = true;
}
}
使用该函数代替 setInterval
。
在你的异步函数中,如果它永远没有理由停止自己:
const intervalFoo = () => {
const checkE2Interval = async(token) => {
console.log('interval async');
await sleep(120); //some long action
// If you had more logic here, you could short-circuit it by checking token.cancelled
};
return mySetInterval(checkE2Interval, 100); //returning id
};
如果确实有理由停止自己,保存cancel
:
const intervalFoo = () => {
let cancel = null;
const checkE2Interval = async(token) => {
console.log('interval async');
await sleep(120); //some long action
// If you had more logic here, you could short-circuit it by checking token.cancelled
// If you wanted not to continue the timer, you'd call cancel here
};
return cancel = mySetInterval(checkE2Interval, 100); //returning id
};
那么,需要取消的地方:
(() => {
const cancellers = [];
cancellers.push(require('./simpleInterval')());
cancellers.push(require('./asyncInterval')());
setTimeout(() => {
cancellers.forEach(cancel => cancel());
}, 1200)
})();
实例:
const sleep = ms => new Promise(resolve => {
setTimeout(resolve, ms);
});
function mySetInterval(callback, ms, ...args) {
let token = {
cancelled: false
};
function wrapper(...args) {
callback(token, ...args);
if (!token.cancelled) {
id = setTimeout(wrapper, ms, ...args);
}
}
let id = setTimeout(wrapper, ms, ...args);
return function cancel() {
clearInterval(id);
token.cancelled = true;
}
}
const intervalFoo = () => {
let cancel = null;
const checkE2Interval = async(token) => {
console.log('interval async');
await sleep(120); //some long action
// If you had more logic here, you could short-circuit it by checking token.cancelled
// If you wanted not to continue the timer, you'd call cancel here
};
return cancel = mySetInterval(checkE2Interval, 100); //returning id
};
(() => {
const cancellers = [];
cancellers.push(intervalFoo());
setTimeout(() => {
console.log("Cancelling");
cancellers.forEach(cancel => {
cancel();
});
}, 1200)
})();
带有 running
标志的实例:
const sleep = ms => new Promise(resolve => {
setTimeout(resolve, ms);
});
function mySetInterval(callback, ms, ...args) {
let token = {
cancelled: false
};
let running = false;
async function wrapper(...args) {
if (!running) {
running = true;
await callback(token, ...args);
running = false;
}
if (!token.cancelled) {
id = setTimeout(wrapper, ms, ...args);
}
}
let id = setTimeout(wrapper, ms, ...args);
return function cancel() {
clearInterval(id);
token.cancelled = true;
}
}
const intervalFoo = () => {
let cancel = null;
const checkE2Interval = async(token) => {
console.log('interval async');
await sleep(120); //some long action
console.log('awake');
// If you had more logic here, you could short-circuit it by checking token.cancelled
// If you wanted not to continue the timer, you'd call cancel here
};
return cancel = mySetInterval(checkE2Interval, 100); //returning id
};
(() => {
const cancellers = [];
cancellers.push(intervalFoo());
setTimeout(() => {
console.log("Cancelling");
cancellers.forEach(cancel => {
cancel();
});
}, 1200)
})();
您可以进一步概括这一点,但您已经掌握了基本思想。