函数防抖(debounce)
当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。如下图,持续触发scroll事件时,并不执行handle函数,当1000毫秒内没有触发scroll事件时,才会延时触发scroll事件。
防抖debounce代码:
// 防抖
function debounce(fn, wait) {
var timeout = null;
return function() {
if(timeout !== null) clearTimeout(timeout);
timeout = setTimeout(fn, wait);
}
}
// 处理函数
function handle() {
console.log(Math.random());
}
// 滚动事件
window.addEventListener('scroll', debounce(handle, 1000));
当持续触发scroll事件时,事件处理函数handle只在停止滚动1000毫秒之后才会调用一次,也就是说在持续触发scroll事件的过程中,事件处理函数handle一直没有执行。
函数防抖:将几次操作合并为一此操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
函数节流(throttle)
当持续触发事件时,保证一定时间段内只调用一次事件处理函数。节流通俗解释就比如我们水龙头放水,阀门一打开,水哗哗的往下流,秉着勤俭节约的优良传统美德,我们要把水龙头关小点,最好是如我们心意按照一定规律在某个时间间隔内一滴一滴的往下滴。如下图,持续触发scroll事件时,并不立即执行handle函数,每隔1000毫秒才会执行一次handle函数。
函数节流主要有两种实现方法:时间戳和定时器。接下来分别用两种方法实现throttle~
节流throttle代码(时间戳+定时器):
// 节流throttle代码(时间戳+定时器):
var throttle = function(func, delay) {
var timer = null;
var startTime = Date.now();
return function() {
var curTime = Date.now();
var remaining = delay - (curTime - startTime);
var context = this;
var args = arguments;
clearTimeout(timer);
if (remaining <= 0) {
func.apply(context, args);
startTime = Date.now();
} else {
timer = setTimeout(func, remaining);
}
}
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));
在节流函数内部使用开始时间startTime、当前时间curTime与delay来计算剩余时间remaining,当remaining<=0时表示该执行事件处理函数了(保证了第一次触发事件就能立即执行事件处理函数和每隔delay时间执行一次事件处理函数)。如果还没到时间的话就设定在remaining时间后再触发 (保证了最后一次触发事件后还能再执行一次事件处理函数)。当然在remaining这段时间中如果又一次触发事件,那么会取消当前的计时器,并重新计算一个remaining来判断当前状态。
函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。
jsonp的产生原因
- 1.Ajax直接请求普通文件存在跨域无权限访问的问题(静态页、动态页、web服务、wcf只要是跨域请求一律不准)
- 2.web的页面上调用js文件是不受跨域的影响(凡拥有src属性的标签都拥有跨域能力script img iframe)
- 3.可以判断 现在想通过纯web端(ActiveX控件、服务端代理、H5之Websocket等方式不算)跨域访问数据就只有一种可能,就是在远程服务器上设法把数据装进js格式的文件里,供客户度调用和进一步处理;
- 4.json的纯字符数格式可以简洁的描述复杂数据还被js原生支持
- 5.web客户端通过与调用脚本一样的方式来调用跨域服务器上动态生成的js格式文件(后缀.json),服务器之所以要动态生成json文件目的把客户端需要的数据装入进去
- 6.客户端在对json文件调用成功后获得自己所需的数据剩下的就按照自己需求进行处理和展现,这种获取远程数据的方式非常像ajax其实并一样
- 7.为了方便客户端使用数据逐渐形成非正式传输协议jsonp
- 该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住json数据 这样客户端就可以随意定制自己的函数来自动处理返回数据
You may have an infinite update loop in a component render function.
组件渲染函数中可能有无限更新循环。
Duplicate keys detected: ‘0’. This may cause an update error.
有可能出现了:key 冲突
出现以上问题是由于循环时key重复导致的。查看问题后发现复制时key重复
JavaScript 中的作用域(scope)是指什么?
javaScript的作用域其实就是指一个变量或函数的作用范围。
作用域的核心思想就是隔离变量污染,在不同作用域下的同名变量是不会有冲突的
解释 JavaScript 中的 null 和 undefined
null表示一个空的对象,什么也没有
undefined 表示声明未赋值
null == undefined //true 隐式转换成布尔类型进行对比
null === undefined //false
js 的typeof返回有哪些数据类型?
string,number,Boolean,undefined,object,function, symbol(ES6中新类型,是一个永远不会相等的数据类型)
浏览器的事件循环
1)为什么会有Event Loop
JavaScript的任务分为两种同步和异步,它们的处理方式也各自不同,同步任务是直接放在主线程上排队依次执行,异步任务会放在任务队列中,若有多个异步任务则需要在任务队列中排队等待,任务队列类似于缓冲区,任务下一步会被移到调用栈然后主线程执行调用栈的任务。
调用栈:调用栈是一个栈结构,函数调用会形成一个栈帧,帧中包含了当前执行函数的参数和局部变量等上下文信息,函数执行完后,它的执行上下文会从栈中弹出。
JavaScript是单线程的,单线程是指 js引擎中解析和执行js代码的线程只有一个(主线程),每次只能做一件事情,然而ajax请求中,主线程在等待响应的过程中回去做其他事情,浏览器先在事件表注册ajax的回调函数,响应回来后回调函数被添加到任务队列中等待执行,不会造成线程阻塞,所以说js处理ajax请求的方式是异步的。
综上所述,检查调用栈是否为空以及讲某个任务添加到调用栈中的个过程就是event loop,这就是JavaScript实现异步的核心。
2)浏览器中的 Event Loop
Micro-Task 与 Macro-Task
浏览器端事件循环中的异步队列有两种:macro(宏任务)队列和 micro(微任务)队列。
常见的 macro-task:setTimeout、setInterval、script(整体代码)、I/O 操作、UI 渲染等。
常见的 micro-task: new Promise().then(回调)、MutationObserve等。
requestAnimationFrame
requestAnimationFrame也属于异步执行的方法,但该方法既不属于宏任务,也不属于微任务。按照MDN中的定义:
window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
requestAnimationFrame是GUI渲染之前执行,但在Micro-Task之后,不过requestAnimationFrame不一定会在当前帧必须执行,由浏览器根据当前的策略自行决定在哪一帧执行。
event loop过程
- 检查macrotask队列是否为空,非空则到2,为空则到3
- 执行macrotask中的一个任务
- 继续检查microtask队列是否为空,若有则到4,否则到5
- 取出microtask中的任务执行,执行完成返回到步骤3
- 执行视图更新
当某个宏任务执行完后,会查看是否有微任务队列。如果有,先执行微任务队列中的所有任务,如果没有,会读取宏任务队列中排在最前的任务,执行宏任务的过程中,遇到微任务,依次加入微任务队列。栈空后,再次读取微任务队列里的任务,依次类推。
解释事件冒泡以及如何阻止它?
事件冒泡:从下至上。当给父子元素的同一事件绑定方法的时候,触发子元素身上的事件,执行完毕之后,也会触发父级元素相同的事件。
注意: addEventListener中有三个属性,第三个属性是布尔值。false为事件冒泡,true为事件捕获
有两种方法可以取消绑定事件的事件冒泡:
1.event.stopPropagation();
事件处理过程中,阻止了事件冒泡,但不会阻击默认行为(它就执行了超链接的跳转)
2.return false;
Listener中有三个属性,第三个属性是布尔值。false为事件冒泡,true为事件捕获
有两种方法可以取消绑定事件的事件冒泡:
1.event.stopPropagation();
事件处理过程中,阻止了事件冒泡,但不会阻击默认行为(它就执行了超链接的跳转)
2.return false;
事件处理过程中,阻止了事件冒泡,也阻止了默认行为(比如刚才它就没有执行超链接的跳转)