// debounce.js
function debounce(fn, delay) {
let timer = null // 2
const _debounce = function() {
if (timer) clearTimeout(timer) // 3
timer = setTimeout(() => { // 4
fn() // 5
timer = null
}, delay)
}
return _debounce // 1
}
注意:执行外部传入的函数之后,要重置定时器变量,不然下一次使用的timer值就是上一次的值,虽然会被上面的判断清空,但是增加了无用的判断。
测试:
<body>
<input type="text" />
</body>
<script>
const inputEl = document.querySelector('input')
let counter = 0
const inputChange = function(event) {
console.log(`发送了 ${++counter} 次网络请求`)
}
inputEl.oninput = debounce(inputChange, 1000)
</script>
运行结果下图:
可以看到,如果是在1秒之内继续输入的话,是不会输出的,所以最后只请求了3次
const inputChange = function(event) {
console.log(`发送了 ${++counter} 次网络请求`, this, event)
}
解决方法:只需要在调用函数时改变this指向,然后传入参数即可,看注释代码:
function debounce(fn, delay) {
let timer = null
const _debounce = function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args) // 改变this指向,然后传入参数
timer = null
}, delay)
}
return _debounce
}
运行结果如下图:
immediate,默认为falseisInvoke,判断是否执行过一次,默认为falsefunction debounce(fn, delay, immediate=false) {
let timer = null
let isInvoke = false // 是否执行过
const _debounce = function(...args) {
if (timer) clearTimeout(timer)
// 判断是否需要立即执行
if (immediate && !isInvoke) {
fn.apply(this, args)
timer = null
isInvoke = true // 改为true
} else {
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
isInvoke = false // 改为true
}, delay)
}
}
return _debounce
}
使用debounce函数时,传入true
inputEl.oninput = debounce(inputChange, 1000, true)
这里看不出效果,可以在自己运行电脑看看效果:
function debounce(fn, delay, immediate=false) {
let timer = null
let isInvoke = false
const _debounce = function(...args) {
if (timer) clearTimeout(timer)
if (immediate && !isInvoke) {
fn.apply(this, args)
timer = null
isInvoke = true
} else {
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
isInvoke = false
}, delay)
}
}
// 取消执行的函数(清除定时器和修改isInvoke即可)
_debounce.cancel = function() {
clearTimeout(timer)
isInvoke = false
}
return _debounce
}
修改测试代码
<body>
<input type="text" />
<button id="cancel">取消</button>
</body>
<script>
const inputEl = document.querySelector('input')
const btn = document.getElementById('cancel')
let counter = 0
const inputChange = function(event) {
console.log(`发送了 ${++counter} 次网络请求`, this, event)
}
const _debounce = debounce(inputChange, 1000)
// 输入框的input事件
inputEl.oninput = _debounce
// 取消按钮的点击事件
btn.onclick = function() {
_debounce.cancel()
}
</script>
运行结果如下图:
输入内容后,在一秒内点击取消按钮就会触发cancel(),清除了定时器,所以也就没有执行输入的回调函数
防抖函数就讲到这里相信同学们应该掌握的差不多了,接下来讲解节流函数
// throttle.js
function throttle(fn, interval) {
let lastTime = 0 // 2
const _throttle = function() {
const nowTime = Date.now() // 3
// 4 计算出还剩余多长时间需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
// 5
fn()
lastTime = nowTime
}
}
return _throttle // 1
}
测代代码:
<body>
<input type="text" />
<script>
const inputEl = document.querySelector('input')
let counter = 0
const inputChange = function(event) {
console.log(`发送了 ${++counter} 次网络请求`)
}
// 输入框的input事件
inputEl.oninput = throttle(inputChange, 2000)
</script>
</body>
运行结果如下图:
说明:2秒内按再多次,回调函数也只执行一次
throttle()时,传入自定义配置变量leading即可,leading默认为true,也就是默认第一次会执行。
lastTime和leading去判断,如果都为false 就让lastTime和nowTime相等,目的是为了让remainTime大于0,从而不去执行回调函数fn(),以达到第一次不会执行的效果。
function throttle(fn, interval, options = { leading: true }) {
const { leading } = options // 取出配置变量
let lastTime = 0
const _throttle = function() {
const nowTime = Date.now()
// 如果第一次的最后时间为0 和 leading为 false时,让lastTime = nowTime(其实就是让remainTime大于0)
if (!lastTime && !leading) lastTime = nowTime
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
fn()
lastTime = nowTime
}
}
return _throttle
}
测试代码:
// 配置 leading 为 false
inputEl.oninput = throttle(inputChange, 2000, {leading: false})
运行结果如下图:
remainTime作为定时器的初始时间。
这里可以延续上面的做法,让开发者在调用throttle()时,传入自定义配置变量trailing为true,默认情况下为false。
具体步骤如下:
trailing,定义变量timer保存定时器returntrailing为true,且timer为空时,执行定时器leading为false,则设置为0,否则设置为当前时间function throttle(fn, interval, options = { leading: true, trailing: false }) {
const { leading, trailing } = options // 取出配置变量
let lastTime = 0
let timer = null // 保存定时器
const _throttle = function() {
const nowTime = Date.now()
if (!lastTime && !leading) lastTime = nowTime
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
// 如果是正常判断下,不需要每一秒都添加定时器,所以要清空定时器
if (timer) {
clearTimeout(timer)
timer = null
}
fn()
lastTime = nowTime
return // 并且return出去
}
// 如果 trailing为true,且timer为空时,执行定时器
if (trailing && !timer) {
timer = setTimeout(() => {
timer = null
// 如果 leading 为false,则设置为 0,否则为当前时间
lastTime = !leading ? 0 : Date.now()
fn()
}, remainTime)
}
}
return _throttle
}
测试代码:
// 输入框的input事件
inputEl.oninput = throttle(inputChange, 2000, {
leading: false,
trailing: true
})
运行结果如下图:
说明:前面两次输出为正常输出,第三次输出是最后一次输入1的输出
实际上,节流函数也可以进行类似防抖函数的【优化this指向和参数】和【取消功能】的版本优化,它们的实现方式都是差不多的,这里就不写了,留给同学们自己完成吧。
每文一句:不要吹灭你的灵感和你的想象力; 不要成为你的模型的奴隶。 ——文森特・梵高本次的分享就到这里,如果本章内容对你有所帮助的话欢迎点赞+收藏。文章有不对的地方欢迎指出,有任何疑问都可以在评论区留言。希望大家都能够有所收获,大家一起探讨、进步!
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我正在尝试用ruby中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
是否可以在应用程序中包含的gem代码中知道应用程序的Rails文件系统根目录?这是gem来源的示例:moduleMyGemdefself.included(base)putsRails.root#returnnilendendActionController::Base.send:include,MyGem谢谢,抱歉我的英语不好 最佳答案 我发现解决类似问题的解决方案是使用railtie初始化程序包含我的模块。所以,在你的/lib/mygem/railtie.rbmoduleMyGemclassRailtie使用此代码,您的模块将在
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD