防抖
防抖 指觸發事件後在 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 ( ) {
}
}