# 1. 节流 throttle
- 一定时间内执行的操作被连续触发只执行最先一次;
- 中心思想:在某段时间内,不管你触发了多少次回调,我都只认第一次,并在计时结束时给予响应。
function throttle (fn, interval) {
let last = 0
return function () {
const context = this
const args = arguments
let now = +new Date()
// 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
if (now - last >= interval) {
last = now
fn.apply(context, args)
}
}
}
// delay时间内,可以为重新生成定时器;但只要delay的时间到了,必须要给用户一个响应。
function throttle (fn, delay) {
let last = 0
let timer = null
return function () {
const context = this
const args = arguments
let now = +new Date()
if (now - last >= delay) {
last = now
fn.apply(context, args)
} else {
// 如果时间间隔小于我们设定的时间间隔阈值,则为本次触发操作设立一个新的定时器
clearTimeout(timer)
timer = setTimeout(function() {
last = now
fn.apply(context, args)
}, delay)
}
}
}
# 2. 防抖 debounce
- 一定时间内执行的操作被连续触发只执行最后一次;
- 中心思想:我会等你到底。在某段时间内,不管你触发了多少次回调,我都只认最后一次。
function debounce (fn, delay) {
let timer = null
return function () {
const context = this
const args = arguments
// 每次事件被触发时,都去清除之前的旧定时器
if (timer) {
clearTimeout(timer)
}
timer = setTimeou(function () {
fn.apply(context, args)
}, delay)
}
}
# 3. 图片懒加载 lazy
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>lazy-load</title>
<style>
.img {
width: 200px;
height:200px;
}
.pic {
height:200px;
}
</style>
</head>
<body>
<div class="container"></div>
<script>
// documentFragment
const oContainer = document.querySelector('.container')
const fragment = document.createDocumentFragment()
for (let i=0; i<60; i++) {
const oDiv = document.createElement('div')
oDiv.className = 'img'
const oImg = document.createElement('img')
oImg.className = 'pic'
oImg.setAttribute('alt', '加载中')
oImg.setAttribute('data-src', `../bg/bg${i+1}.png`)
oDiv.appendChild(oImg)
fragment.appendChild(oDiv)
}
oContainer.appendChild(fragment)
// 图片
const imgs = document.querySelectorAll('img')
const viewHeight = window.innerHeight || document.documentElement.clientHeight
let num = 0
function lazyload () {
for (let i=num; i<imgs.length; i++) {
// 用可视区域高度减去元素顶部距离可视区域顶部的高度
let dis = viewHeight - imgs[i].getBoundingClientRect().top
// 如果可视区域高度大于等于元素顶部距离可视区域顶部的高度,说明元素露出
if (dis >= 0) {
imgs[i].src = imgs[i].getAttribute('data-src')
num = i + 1
}
}
}
// throttle
function throttle (fn, delay) {
let last = 0
let timer = null
return function () {
const context = this
const args = arguments
let now = +new Date()
if (now - last >= delay) {
last = now
fn.apply(context, args)
} else {
clearTimeout(timer)
timer = setTimeout(function() {
last = now
fn.apply(context, args)
}, delay)
}
}
}
lazyload()
window.addEventListener('scroll', throttle(lazyload, 300), false)
</script>
</body>
</html>
# 4. promise
手写Promise原理 (opens new window)
class MyPromise {
constructor (fn) {
this.state = 'pending'
this.result = null
this.fulfilledCb = []
this.rejectedCb = []
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
try {
fn(this.resolve, this.reject)
} catch (err) {
this.reject(err)
}
}
resolve (val) {
if (this.state !== 'pending') {
return
}
this.state = 'fulfilled'
this.result = val
while (this.fulfilledCb.length) {
this.fulfilledCb.shift()(val)
}
}
reject (reason) {
if (this.state !== 'pending') {
return
}
this.state = 'rejected'
this.result = reason
while (this.rejectedCb.length) {
this.rejectedCb.shift()(reason)
}
}
then (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
onRejected = typeof onRejected === 'function' ?
onRejected : reason => { throw reason }
let thenPromise = new MyPromise((resolve, reject) => {
setTimeout(() => {
try {
const resolvePromise = cb => {
const x = cb(this.result)
if (x === thenPromise) {
throw new Error('不能返回自身。。。')
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
} catch (err) {
reject(err)
throw new Error(err)
}
})
})
if (this.state === 'fulfilled') {
onFulfilled(this.result)
} else if (this.state === 'rejected') {
onRejected(this.result)
} else {
this.fulfilledCb.push(onFulfilled.bind(this))
this.rejectedCb.push(onRejected.bind(this))
}
return thenPromise
}
}
const test1 = new MyPromise((resolve, reject) => {
resolve('成功-test1')
})
console.log(test1) // MyPromise { PromiseState: 'fulfilled', PromiseResult: '成功' }
const test2 = new MyPromise((resolve, reject) => {
reject('失败-test2')
})
console.log(test2) // MyPromise { PromiseState: 'rejected', PromiseResult: '失败' }
const test3 = new MyPromise((resolve, reject) => {
throw('失败-throw-test3')
})
console.log(test3) // MyPromise { PromiseState: 'rejected', PromiseResult: '失败' }
const test4 = new MyPromise((resolve, reject) => {
resolve('成功-then-test4')
}).then(res => console.log(res), err => console.log(err))
const test5 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('失败-setTimeout-test5')
}, 3000)
}).then(res => console.log(res), err => console.log(err))
const test6 = new Promise((resolve, reject) => {
resolve(100) // 输出 状态:成功 值: 200
// reject(100) // 输出 状态:成功 值:300
}).then(res => 2 * res, err => 3 * err)
.then(res => console.log('成功-链式-test6', res), err => console.log('失败', err))
const test7 = new Promise((resolve, reject) => {
resolve(100) // 输出 状态:失败 值:200
// reject(100) // 输出 状态:成功 值:300
// 这里可没搞反哦。真的搞懂了,就知道了为啥这里是反的
}).then(res => new Promise((resolve, reject) => reject(2 * res)), err => new Promise((resolve, reject) => resolve(3 * err)))
.then(res => console.log('成功-链式-test7', res), err => console.log('失败-链式-test7', err))
// 未实现
const test8 = new MyPromise((resolve, reject) => {
resolve(1)
}).then(res => console.log(res), err => console.log(err))
console.log(2)