function doSth(fn) {
// only code here
}
const fn = doSth(()=>{
console.log('hello world');
})
setInterval(() => {
fn()
},10)
此功能需要输出" hello world"每秒一次,我试图在封闭内部使用类似功能节流的东西,但它没有像我预期的那样工作:
function doSth(fn) {
return function () {
clearTimeout(fn.tid)
fn.tid = setTimeout(function () {
fn()
},1000)
}
}
const fn = doSth(()=>{
console.log('hello world');
})
setInterval(() => {
fn()
},10)
我预计每1秒会有一个setTimeout函数,额外的调用将被取消,但它似乎很混乱。是因为doSth函数内部的闭包还是我使用setTimeout的方式?
答案 0 :(得分:1)
如果我理解正确,你似乎必须将setInterval移动到doSth(fn)函数中。
function doSth(fn) {
setInterval(() => {
fn();
}, 10)
}
const fn = doSth(() => {
console.log('hello world');
})
答案 1 :(得分:1)
使用setTimeout
无法解决您的问题。这是合乎逻辑的。 setTimeout
做的是延迟某事的执行。因此,如果你有setInterval
每秒100次(每10毫秒),你在其中调用setTimeout
,你所做的就是每秒100次调用setTimeout
,这仍然会打印{{ 1}}每秒100次:
hello world
解决方案是计算您被调用的时间,并且每100次 100 times per second 100 times per second
setInterval
setInterval ╲
setInterval ╲╲
. ╲╲╲ 1 second later
. ╲╲╲
. ╲╲╲
╲╲╲______________ setTimeout
╲╲______________ setTimeout
╲______________ setTimeout
.
.
调用您的函数打印hello world
。让我们从最简单的方法开始:全局变量:
setInterval
这是有效的,但我们引入了一个丑陋的全局变量。幸运的是,我们知道var counter = 0;
function doSth(fn) {
counter ++;
if (counter >= 100) { // once per second
counter = 0;
fn();
}
}
不会直接调用我们的函数。相反,它希望我们的函数返回另一个它将调用的函数:
setInterval
这意味着我们需要编写这样的函数:
const fn = doSth(...);
这非常幸运,因为闭包是一种允许函数共享局部变量的机制。基本上它使局部变量的行为有点像全局变量,但不会污染全局命名空间。现在我们可以简单地将全局变量移动到闭包中:
var counter = 0;
function doSth(fn) { // <──┐
return function(){ // <──┴─ oh look, a closure!
counter ++;
if (counter >= 100) { // once per second
counter = 0;
fn();
}
}
}
答案 2 :(得分:0)
如果你的问题是:
我预计每1秒会有
setTimeout
个功能
这就是答案。现在它是如何工作的?好setInterval
和setTimeout
基本上会尝试做同样的事情,但对于您的案例setInterval
方法将比setTimeout
更准确。为什么?因为setTimeout
等待1000毫秒,运行闭包然后设置另一个超时。因此等待时间实际上比1000ms
多一点(或者如果您的函数需要很长时间才能执行,则会更多)。
由于JavaScript不是多线程语言,setInterval
也会延迟,这意味着 - 如果脚本的其他部分正在运行 - 则间隔必须等待完成。
查看我为您制作的这个例子。
更新我将setTimeout
放在setInterval
内请查看。
var speed = 1000; // One second
var start = +new Date;
var icounter = 0;
var tcounter = 0;
var fnLabel = '<td>fn</td><td>';
var setIntervalLabel = '<td>setInterval</td><td>';
var etdtd = '</td><td>';
var i = document.querySelector('#i');
var t = document.querySelector('#t');
setInterval(() => {
fn();
var time = (new Date - start) / 1000;
var avg = tcounter++/ time;
t.innerHTML = setIntervalLabel + tcounter + etdtd + time.toFixed(3) + etdtd + avg.toFixed(6) + etdtd + '</td>';
}, 10)
const fn = doSth(() => {
var time = (new Date - start) / 1000;
var avg = icounter++/ time;
i.innerHTML = fnLabel + icounter + etdtd + time.toFixed(3) + etdtd + avg.toFixed(6) + etdtd + 'Hello ' + icounter + '</td>';
});
function doSth(fn) {
var counter = 0;
return function() {
counter++;
if (counter > 99) { // once per second
counter = 0;
fn();
}
}
}
table,
th,
td {
border: 1px solid black
}
th,
td {
padding: .2em .4em .3em
}
th {
font-weight: bold;
background-color: #89C
}
<table>
<tr>
<th>type</th>
<th>calls</th>
<th>seconds</th>
<th>average calls/second</th>
<th>Say Hello world!</th>
</tr>
<tr id="i">
<td>fn</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td></td>
</tr>
<tr id="t">
<td>setIntervalLabel</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td></td>
</tr>
</table>