前端analysis | 3w & 1h

《Lodash源码阅读笔记》- delay

2020-01-19

需求背景

D3 tooltip内容过多,需要展示滚动条。鼠标离开定位后,立刻触发mouseout,此时tooltip会隐藏。
但是,需求是不能隐藏。那么久从离开到隐藏之间,存在一定时间的隐藏。

用delay实现

1
2
3
4
5
6
7
8
# 全局变量控制
cancelDealHandler(){
if(something){ //取消
cancle = true;
}else {
cancle = false;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
line.on('mouseover',() => {
//触发tooltip显示
showTip();
}).on('mouseout',() => {
_.delay(() => {
if(cancle){ //取消隐藏,全局变量控制
return;
}
hideTip();
},3000);
})
;

上述方法实现总结

  • 确实能做到tip显示控制
  • 不过,存在严重缺陷,小伙伴你知道吗?

我们查看下delay源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Invokes `func` after `wait` milliseconds. Any additional arguments are
* provided to `func` when it's invoked.
*
* @since 0.1.0
* @category Function
* @param {Function} func The function to delay.
* @param {number} wait The number of milliseconds to delay invocation.
* @param {...*} [args] The arguments to invoke `func` with.
* @returns {number} Returns the timer id.
* @example
*
* delay(text => console.log(text), 1000, 'later')
* // => Logs 'later' after one second.
*/
function delay(func, wait, ...args) {
if (typeof func !== 'function') {
throw new TypeError('Expected a function')
}
return setTimeout(func, +wait || 0, ...args)
}

export default delay

哦哦,原来,底层使用setTimeout!!!

上述方法的问题:

* 没调用一次delay,触发一次setTimeout
* 大量的mouseout,那么久会产生很多setTimout
* 过多的setTimout,会进入排队等待执行,
* 当某次代码执行到hideTip()前,cancel= true,但是此时依旧会隐藏tip.
* 没有及时清空timer,虽然只会执行一次

改进

1
2
3
4
5
6
7
8
# 全局变量控制
cancelDealHandler(){
if(something){ //取消
clearTimeout(delayTimer);
}else {
hideTip();
}
}
1
2
3
4
5
6
7
8
9
10
11
line.on('mouseover',() => {
//触发tooltip显示
clearTimeout(delayTimer);
showTip();
}).on('mouseout',() => {
clearTimeout(delayTimer);
delayTimer = _.delay(() => {
hideTip();
},3000);
})
;
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏