# 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)