- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
假设存在随机序列的外部操作(例如滚动事件)。我需要立即处理第一个 Action ,然后取消所有间隔小于某个给定增量的 Action ,然后处理下一个应该为该增量延迟的 Action 。应以相同的方式处理进一步的操作。
这看起来像是 debounce-immediate 和 simple debounce 的组合。我准备了一张图表来展示这个想法。
这里最好的解决方案/方法是什么?不知有没有现成的图案...
更新
我要感谢所有参与者!为了研究,我用 四个 答案中建议的五个不同实现创建了 plunker:https://plnkr.co/N9nAwQ .
const handler = [
processEvent, // normal
debounceNext(processEvent, DELAY), // dhilt
makeRateLimitedEventHandler(DELAY, processEvent), // user650881
debounceWithDelay(processEvent, DELAY, 0), // willem-dhaeseleer
_.debounce(processEvent, DELAY, {leading: true}) // lodash debounce + leading,
debounceish(DELAY, processEvent) //Mikk3lRo
];
一个好消息是 Lodash 有一个 leading-flag debounce 实现来解决这个问题(感谢 Willem D'Haeseleer)。和 here是来自 Mikk3lRo 回答的很酷的演示,他还提供了一些有用的综合。
我调查了来源和结果:形式为 visual指向内存分配的东西...我没有发现任何性能问题,而且 View 似乎还不错。所以最后的比率就是代码本身。所有源代码都已转换为 ES6(如您在 Plunker 中所见),因为我可以对它们进行全面比较。我排除了我的 own try (尽管我喜欢它的外观,但它有点过分)。时间戳版本非常有趣! postDelay 版本很好,虽然它不是一个请求的功能(所以 snippet demo 有两个 lodash 演示的双重延迟)。
我决定不依赖 lodash(换句话说,我当然会使用带前导选项的 lodash debounce),所以我选择了 Mikk3lRo 的 debounceish
。
PS 我想分享那笔小赏金(不幸的是没有这样的选择)或者甚至从我的声誉中获得更多分数(但不是 200,太多了,会对只有 100 的获胜者不公平)。我什至不能投票两次......没关系。
最佳答案
使用单个计时器的 vanilla JS 中一个非常简单的解决方案:
function debounceish(delta, fn) {
var timer = null;
return function(e) {
if (timer === null) {
//Do now
fn(e);
//Set timer that does nothing (but is not null until it's done!)
timer = setTimeout(function(){
timer = null;
}, delta);
} else {
//Clear existing timer
clearTimeout(timer);
//Set a new one that actually does something
timer = setTimeout(function(){
fn(e);
//Set timer that does nothing again
timer = setTimeout(function(){
timer = null;
}, delta);
}, delta);
}
};
}
function markEvt(e) {
var elm = document.createElement('div');
elm.style.cssText = 'position:absolute;background:tomato;border-radius:3px;width:6px;height:6px;margin:-3px;';
elm.style.top = e.clientY + 'px';
elm.style.left = e.clientX + 'px';
document.body.appendChild(elm);
}
document.addEventListener('click', debounceish(2000, markEvt));
<p>Click somewhere (2000ms delta) !</p>
使用相同类型的可视化比较 6 个提案:
var methods = {
default: function(delay, fn) {
return fn;
},
dhilt_debounceNext: (delay, cb) => {
let timer = null;
let next = null;
const runTimer = (delay, event) => {
timer = setTimeout(() => {
timer = null;
if(next) {
next(event);
next = null;
runTimer(delay);
}
}, delay);
};
return (event) => {
if(!timer) {
cb(event);
}
else {
next = cb;
clearTimeout(timer);
}
runTimer(delay, event);
}
},
Mikk3lRo_debounceish(delta, fn) {
var timer = null;
return function(e) {
if (timer === null) {
//Do now
fn(e);
//Set timer that does nothing (but is not null until it's done!)
timer = setTimeout(function(){
timer = null;
}, delta);
} else {
//Clear existing timer
clearTimeout(timer);
//Set a new one that actually does something
timer = setTimeout(function(){
fn(e);
//Set timer that does nothing again
timer = setTimeout(function(){
timer = null;
}, delta);
}, delta);
}
};
},
user650881_makeRateLimitedEventHandler: function(delta_ms, processEvent) {
var timeoutId = 0; // valid timeoutId's are positive.
var lastEventTimestamp = 0;
var handler = function (evt) {
// Any untriggered handler will be discarded.
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = 0;
}
var curTime = Date.now();
if (curTime < lastEventTimestamp + delta_ms) {
// within delta of last event, postpone handling
timeoutId = setTimeout(function () {
processEvent(evt);
}, delta_ms);
} else {
// long enough since last event, handle now
processEvent(evt);
}
// Set lastEventTimestamp to time of last event after delta test.
lastEventTimestamp = Date.now();
};
return handler;
},
Willem_DHaeseleer_debounceWithDelay: (delay, func) => {
let postDebounceWait;
let timeOutLeading = false;
const debounced = _.debounce((...args) => {
// wrap the handler so we can add an additional timeout to the debounce invocation
if (timeOutLeading) {
/*
for the first invocation we do not want an additional timeout.
We can know this is the leading invocation because,
we set timeOutLeading immediately to false after invoking the debounced function.
This only works because the debounced leading functionality is synchronous it self.
( aka it does not use a trampoline )
*/
func(...args);
} else {
postDebounceWait = setTimeout(() => {
func(...args)
}, delay);
}
}, delay, {leading: true});
return (...args) => {
// wrap the debounced method it self so we can cancel the post delay timer that was invoked by debounced on each invocation.
timeOutLeading = true;
clearTimeout(postDebounceWait);
debounced(...args);
timeOutLeading = false;
}
},
Willem_DHaeseleer_lodashWithLeading: (delta, cb) => {
return _.debounce(cb, delta * 2, {leading: true});
},
Javier_Rey_selfCancelerEventListener: function (delta, fn) {
return function(ev) {
var time = new Date().getTime();
if (ev.target.time && time - ev.target.time < delta) {return;}
ev.target.time = time;
fn(ev);
};
},
};
var method_count = 0;
var colors = ['grey', 'tomato', 'green', 'blue', 'red', 'orange', 'yellow', 'black'];
function markEvt(method) {
var style = 'position:absolute;border-radius:3px;width:6px;height:6px;margin:-3px;';
style += 'background:' + colors[method_count] + ';';
if (method_count > 0) {
style += 'transform:rotate(' + Math.floor(360 * method_count / (Object.keys(methods).length - 1)) + 'deg) translateY(-8px);';
}
var elm = document.createElement('div');
elm.innerHTML = '<span style="width:.8em;height:.8em;border-radius:.4em;display:inline-block;background:' + colors[method_count] + '"></span> ' + method;
document.body.appendChild(elm);
method_count++;
return function(e) {
elm = document.createElement('div');
elm.style.cssText = style;
elm.style.top = e.clientY + 'px';
elm.style.left = e.clientX + 'px';
document.body.appendChild(elm);
};
}
for (var method in methods) {
document.addEventListener('click', methods[method](2000, markEvt(method)));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
请注意,我需要对某些方法进行细微调整以获得通用接口(interface)。改编 Cully 的答案比我愿意付出的努力要多,因为考虑到评论表明它无论如何都没有按照 OP 的要求去做。
很明显,Javier Rey 的方法与其他方法完全不同。 Dhilt,user650881 和我自己的方法似乎是一致的。 Willem D'Haeseleer 的两种方法都有双倍的延迟(和其他细微差别),但似乎也表现一致。据我所知,双重延迟完全是故意的,尽管我对 OP 的理解不是这样。
I would say that Willem D'Haeseleer's lodash method is without a doubt the simplest - if you already use lodash that is. Without external dependencies my method is IMO simplest - but I may be biased on that one ;)
关于javascript - 基于选择性超时的事件处理 : immediate first, 接下来去抖动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46633701/
我正在阅读一些有关使用 curses 用 c 编写的旧银行柜员管理工具的源代码,这里有一些我无法理解的代码: main(int argc, char *argv[]) { int h1, h2
我已经在 Google Play 商店中启动了应用程序,对于该应用程序,我需要实现立即应用程序更新,以解决已经在使用我的应用程序的问题 我已经尝试过 Github 示例,这些示例是灵活更新而不是立即更
我有简单的启动服务功能并重复他: mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); Pe
我需要一个 EXECUTE IMMEDIATE 将其结果返回到一个表类型(AS TABLE OF)中 如果立即执行返回单个值,我可以使用“INTO somevariable”保存结果 但是,我的立即执
只是想知道这是否是对多列和多行执行立即执行并将其分配给变量的正确方法?我尝试查看示例,但不确定我是否正确连接了这些行? sql_stmt VARCHAR2(200); sql_stmt:
我来自 Eclipse,我习惯于立即报告整个项目的错误。 假设我有这个功能: public void test() { //Do something } 我把它改成 public void te
什么是“立即模式”?给出一个代码示例。 什么时候必须使用立即模式而不是保留模式?使用每种方法的优点和缺点是什么? 最佳答案 “立即模式”的一个示例是使用 glBegin和glEnd与 glVertex
我有一个使用 EXECUTE IMMEDIATE 调用的存储过程。我面临的问题是,直接调用过程与使用 EXECUTE IMMEDIATE 调用过程时的解释计划不同。这导致执行时间增加了 5 倍。计划之
这个问题不太可能对任何 future 的访客有帮助;它只与一个较小的地理区域、一个特定的时间点或一个非常狭窄的情况相关,通常不适用于全世界的互联网受众。如需帮助使此问题更广泛适用,visit the
我有一个表,其中存储了某些条件以及输入参数,如下所示: CONDITION | INPUT_PARAMS ----------------------
我有一个网络应用程序,它创建一些自定义消息并将它们按顺序缓冲在 FIFO 队列中,直到调用 send() 方法,然后所有这些消息都被传输到它们的预期目的地。 还需要提供一种允许“立即发送”功能的方法,
如果存储过程旨在减轻 SQL 注入(inject)攻击,为什么在存储过程中允许 EXECUTE IMMEDIATE?以下问题的公认答案将它们称为针对此类攻击的步骤: What is a stored
我有一个关于“立即执行”的问题。 我在下一个 plsql 语句中动态更改了表名 DECLARE TYPE CurTyp IS REF CURSOR; cur CurTyp; str1 VARCHAR2
最初 immediate标志仅用于 ActionSource界面。但后来它被添加到 EditableValueHolder界面也。设计决策的原因是什么? 最佳答案 它用于对多个 EditableVal
这个问题是关于不允许“创建”权限的环境。 版本是: Oracle 数据库 10g 和 PL/SQL 8.0.0.1480 下面是一个小示例,展示了我正在尝试完成的任务,即循环遍历集合中的一组“字段”并
我有一个使用 EXECUTE IMMEDIATE 的存储过程命令执行一个很长的字符串。如何支持很长的字符串并将数据返回到refcursor? 最佳答案 假设您的 SQL 不超过 32K(正如@Tony
嗨,我真的是 Jsf 和 Primefaces 世界的新手,我有一个关于 Primefaces 轮询组件的简单查询,如下所示。 我有一个登录页面,一旦用户通过身份验证,我将他重定向到welcome.x
在调试断点中,是否可以尝试Dart表达式并执行命令? 就像在Chrome Developer Bar,Firebug或Visual Studio立即窗口中一样。 最佳答案 不幸的是还没有。 标记htt
这个问题已经有答案了: Create user from string variables in a PL/SQL block (1 个回答) 已关闭 6 年前。 我正在 Oracle 数据库上编写
我有以下组件: @Component( label = "Service name", description = "Service description", metatyp
我是一名优秀的程序员,十分优秀!