防抖
防抖 指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
let box = document. getElementById ( 'box' )
let num = 1 ;
function add ( ) {
box. innerHTML = num++
}
function debounce ( fn, time) {
let timer = null ;
return function ( ) {
clearTimeout ( timer)
timer = setTimeout ( ( ) => {
fn. call ( this )
} , time)
}
}
box. onmousemove = debounce ( add, 1000 )
function debounce ( fn, time) {
let timer = null ;
return function ( ) {
clearTimeout ( timer) ;
let now = ! timer
timer = setTimeout ( ( ) => {
timer = null ;
} , time)
if ( now) {
fn. call ( this )
}
}
}
box. onmousemove = debounce ( add, 1000 )
function debounce ( fn, time, immediate) {
let timer
return function ( ) {
if ( immediate) {
clearTimeout ( timer) ;
let now = ! timer;
timer = setTimeout ( ( ) => {
timer = null ;
} , time)
if ( now) {
fn. call ( this )
} ;
} else {
clearTimeout ( timer) ;
timer = setTimeout ( ( ) => {
fn. call ( this )
} , time) ;
}
}
}
box. onmousemove = debounce ( add, 1000 , true )
节流
节流 指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
function throttle ( fn, time) {
let previous = 0 ;
return function ( ) {
let now = Date. now ( ) ;
if ( now - previous >= time) {
fn. call ( this ) ;
previous = now;
}
}
}
box. onmousemove = throttle ( add, 2000 ) ;
function throttle ( fn, time) {
let timer;
return function ( ) {
if ( ! timer) {
timer = setTimeout ( ( ) => {
timer = null
fn. call ( this )
} , time)
}
}
}
box. onmousemove = throttle ( add, 2000 ) ;
function throttle ( fn, time, type) {
if ( type === 1 ) {
var previous = 0 ;
} else {
var timer;
}
return function ( ) {
if ( type === 1 ) {
let now = Date. now ( ) ;
if ( now - previous >= time) {
fn. call ( this ) ;
previous = now;
}
} else if ( type === 2 ) {
if ( ! timer) {
timer = setTimeout ( ( ) => {
timer = null ;
fn. call ( this ) ;
} , time) ;
}
}
}
}
box. onmousemove = throttle ( add, 2000 , 1 ) ;
定时器同异步
时间循环流程
执行栈 等待栈
调用栈中的同步任务都执行完毕,栈内被清空了,就代表主线程空闲了,这个时候就会去任务队列中按照顺序读取一个任务放入到栈中执行。每次栈内被清空,都会去读取任务队列有没有任务,有就读取执行,一直循环读取-执行的操作,就形成了事件循环。
当浏览器解析JS时,会先把所有同步代码执行完,然后再执行异步
js是单线程 js同一时间只能执行一行代码
浏览器是多线程
线程是一个小的进程
异步 :定时器 ajax 事件(onload,onclick,promise,async,await)
1.如果两个定时器都在for循环的上面,谁的时间小,先执行谁,如果时间相同 按顺序执行
2.当同步代码执行完毕,会对异步任务进行比较,谁先到达执行时间,先执行谁
当js运行时,分为主任务队列和等待任务队列,主任务都是同步的,异步是等待任务队列,只有主任务队列执行完毕,才会执行等待任务队列
js将请求数据这个任务交给了浏览器,浏览器去向服务器请求数据,服务器把数据返回给浏览器
setInterval 每隔多长时间执行一次
setTimeout 到了一定时间执行一次
浏览器最小识别时间:谷歌 5 - 6 ms 火狐 10 - 12 IE 13 - 15
setTimeout 当代码运行到setTimeout 这里时,浏览器会给当前定时器记录一个开始时间
function fn ( ) {
var a = setTimeout ( function ( ) { } , 1000 )
console. log ( a) ;
}
var timer = setTimeout ( function ( a, b) {
console. log ( a, b) ;
return 100
} , 2000 , 1 , 2 )
fn ( ) ;
console. log ( timer) ;
计算for 循环的时间
var cur = Date. now ( ) ;
for ( var i = 0 ; i< 10000000 ; i++ ) {
}
console. log ( Date. now ( ) - cur) ;
setTimeout ( function ( ) {
console. log ( 100 ) ;
} , 20 )
console. log ( 300 ) ;
setTimeout ( function ( ) {
console. log ( 400 ) ;
} , 10 )
for ( var i= 0 ; i< 1000000 ; i++ ) {
}
console. log ( 200 ) ;
window. onload = function ( ) {
setTimeout ( function ( ) {
console. log ( 500 ) ;
} , 20 )
console. log ( 600 ) ;
setTimeout ( function ( ) {
console. log ( 700 ) ;
} , 10 )
for ( var i= 0 ; i< 1000000 ; i++ ) {
}
console. log ( 800 ) ;
}
多方向运动公式
function linear ( t, b, c, d) {
return c / d * t + b
}
let box = document. getElementById ( 'box' ) ;
let target = {
left: 500 ,
top: 300 ,
width: 200 ,
height: 200
}
let curStart = getComputedStyle ( box)
let begin = {
left: parseFloat ( curStart. left) ,
top: parseFloat ( curStart. top) ,
width: parseFloat ( curStart. width) ,
height: parseFloat ( curStart. height) ,
} ;
let duration = 3000 ;
let change = { } ;
let timer = null ;
for ( let key in target) {
change[ key] = target[ key] - begin[ key]
}
box. onclick = function ( ) {
clearInterval ( timer)
let t = 0
timer = setInterval ( ( ) => {
t += 20 ;
for ( let key in change) {
let cur = linear ( t, begin[ key] , change[ key] , duration) ;
box. style[ key] = cur + 'px' ;
}
if ( t >= duration) {
clearInterval ( timer)
timer = setInterval ( ( ) => {
t -= 20 ;
for ( let key in change) {
let cur = linear ( t, begin[ key] , change[ key] , duration) ;
box. style[ key] = cur + 'px' ;
if ( t<= 0 ) { {
clearInterval ( timer)
} }
}
} , 20 ) ;
}
} , 20 ) ;
}
promise
Promise 是ES6中新增的一个类,专门用来解决异步回调地狱的问题,将异步代码同步显示出来;
promise 三个状态 : Pending fulfilled rejected
改变状态有两种可能 pending-->fulfilled pending--> rejected
$. ajax ( {
url: "time/ww" ,
success: function ( data) {
$. ajax ( {
当第一个请求成功以后再发第二个
success: function ( ) {
$. ajax ( {
} )
}
} )
}
} )
axios fetch
let p = new Promise ( function ( resolve, reject) {
resolve ( ) ;
reject ( ) ;
} ) . then ( function ( ) {
console. log ( 1 ) ;
} , function ( ) {
console. log ( 2 ) ;
} ) . then ( function ( ) {
} , function ( ) {
} )
promise的回调函数 是同步的 then对应的函数是异步的
定时器是等待任务 又分为宏任务和微任务,当执行栈主任务队列执行完,要执行等待任务,在执行等待任务时,先执行微任务,后执行宏任务
then 微任务 定时器 宏任务
setTimeout ( function ( ) {
console. log ( 500 ) ;
} , 0 )
console. log ( 100 ) ;
let p = new Promise ( function ( resolve, reject) {
console. log ( 300 ) ;
resolve ( ) ;
console. log ( 200 ) ;
} ) ;
p. then ( function ( ) {
console. log ( 400 ) ;
} )
console. log ( 600 ) ; * /
Promise.all()
Promise.all() 私有属性 用于多个实例 返回一个新Promise实例
只有当p1,,p2,p3状态全部为filfulled,那么新实例才是成功的
只要有一个rejected 就是失败
let p1 = new Promise ( function ( resolve, reject) {
setTimeout ( function ( ) {
resolve ( 100 )
} , 3000 )
} )
let p2 = new Promise ( function ( resolve, reject) {
setTimeout ( function ( ) {
resolve ( 200 )
} , 2000 )
} )
let p3 = new Promise ( function ( resolve, reject) {
setTimeout ( function ( ) {
resolve ( 300 )
} , 4000 )
} )
let p = Promise. all ( [ p1, p2, p3] )
p. then ( function ( data) {
console. log ( data) ;
} ) . catch ( function ( data) {
console. log ( data) ;
} )
Promise.prototype.catch()
let p = new Promise ( function ( resolve, reject) {
resolve ( )
} )
p. then ( function ( ) {
console. log ( 1 ) ;
throw new Error ( )
} ) . then ( function ( ) {
console. log ( 5 ) ;
} ) . catch ( function ( ) {
console. log ( 2 ) ;
} )
Promise.prototype.finally()
finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作
try {
console. log ( 2 ) ;
} catch ( e) {
console. log ( 1 ) ;
} finally {
console. log ( 3 ) ;
}
let p = new Promise ( function ( resolve, reject) {
resolve ( )
} )
p. then ( function ( ) {
console. log ( 1 ) ;
} ) . then ( function ( ) {
console. log ( 5 ) ;
} ) . catch ( function ( ) {
console. log ( 2 ) ;
} ) . finally ( function ( ) {
console. log ( 1000 ) ;
} )
console. log ( 999 ) ;
Promise.race()
Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
let p1 = new Promise ( function ( resolve, reject) {
setTimeout ( function ( ) {
resolve ( 100 )
} , 3000 )
} )
let p2 = new Promise ( function ( resolve, reject) {
setTimeout ( function ( ) {
reject ( 200 )
} , 5000 )
} )
let p3 = new Promise ( function ( resolve, reject) {
setTimeout ( function ( ) {
resolve ( 300 )
} , 4000 )
} )
let p = Promise. race ( [ p1, p2, p3] )
p. then ( function ( data) {
console. log ( '成功' ) ;
} ) . catch ( function ( data) {
console. log ( '失败' ) ;
} )
Promise.resolve:
将一个对象转成一个promise的实例;返回值可以调用then方法
Promise. resolve ( "foo" ) . then ( function ( ) {
} )
new Promise ( function ( resolve, reject) {
resolve ( "foo" )
} ) ;
Promise. reject ( "foo" ) . then ( function ( ) {
} )
new Promise ( function ( resolve, reject) {
reject ( "foo" )
} ) ;
let p = Promise. resolve ( ) ;
p. then ( function ( ) {
} )
let a = {
then: function ( ) {
}
}