util.js

/* eslint-disable no-unused-vars */
/**
 * 通用函数。
 * @module common
 */

/**
 * @static
 * @description 函数柯里化。
 * @example
 * function add(a, b) {
 *  return a + b
 * }
 * var curriedAdd = curry(add)
 * var addFive = curriedAdd(5)
 * var result = [0, 1, 2, 3, 4, 5].map(addFive)
 * // [5, 6, 7, 8, 9, 10]
 * @param {function} fn 需要柯里化的函数,函数“无默认值的参数”个数不为0。
 * @return {function} 柯里化后的函数。
 */

function curry (fn) {
    // fn的无默认值参数的个数
    if (fn.length === 0) {
        return fn
    }

    function _curried (depth, args) {
        return function (newArgument) {
            // 需要传入fn需要的参数个数,才会返回值
            if (depth - 1 === 0) {
                return fn(...args, newArgument)
            }
            return _curried(depth - 1, [...args, newArgument])
        }
    }

    return _curried(fn.length, [])
}

/**
 * @static
 * @description 最大重复数数量
 * @example
 * countMaxDuplicateNumber([1,2,2,5,5,5])
 * // 3
 * @param {Array<Number>} array 数字数组
 * @return {Number} 数量
 */

function countMaxDuplicateNumber (array) {
    if (!array.length) {
        return 0
    }
    const sortedAry = array.sort((a, b) => {
        return a - b
    })
    let count = 1
    let max = 1

    for (let i = 1; i < sortedAry.length; i++) {
        if (sortedAry[i - 1] === sortedAry[i]) {
            max++
        } else {
            if (max > count) {
                count = max
            }
            max = 1
        }
    }
    return count
}

/**
 * @static
 * @description requestAnimationFrame 节流函数。
 * @param {Function} fn 数字数组。
 * @return {Function} 节流函数。
 */

function throttle (fn) {
    let curTick = false
    const that = this
    const params = [...arguments]

    params.shift()
    return function () {
        const curParams = [...arguments]

        if (!curTick) {
            curTick = true
            requestAnimationFrame(() => {
                fn.apply(that, [...curParams, params])
                curTick = false
            })
        }
    }
}

/**
 * @static
 * @description 依次按序执行 promise,全部调用完毕后返回一个新的 promise。
 * @example
 * function getA() {
 *     return new Promise((resolve, reject) => {
 *         get('/user/a', (status, res) => {
 *             if (status == 200) {
 *                 resolve(res)
 *             } else {
 *                 reject('error')
 *             }
 *         })
 *     })
 * }
 *
 * function getB(dataA) {
 *     return new Promise((resolve, reject) => {
 *         get('/user/b', dataA, (status, res) => {
 *             if (status == 200) {
 *                 resolve(res)
 *             } else {
 *                 reject('error')
 *             }
 *         })
 *
 *     })
 * }
 *
 * function getC(dataB) {
 *     return new Promise((resolve, reject) => {
 *         get('/user/c', dataB, (status, res) => {
 *             if (status == 200) {
 *                 resolve(res)
 *             } else {
 *                 reject('error')
 *             }
 *         })
 *
 *     })
 * }
 *
 * promiseOrder([getA,getB,getC]).then((res)=>{
 *     console.log('success');
 *     console.log(res);
 * })
 * @param {Arry} pFAry 数组,元素是函数,函数返回 promise 对象。
 * 函数接收上一次 promise resolve 的参数。
 * @returns {Promise} 新的 fulfilled 状态 promise 对象。
 * 传递最后一次 promise resolve 的参数。
 */

function promiseOrder (pFAry) {
    return new Promise((resolve, reject) => {
        let promise = Promise.resolve()

        // 由于要最后一个promise执行完毕,才resolve,这里需要pFAry.length + 1
        for (let i = 0; i < pFAry.length + 1; i++) {
            promise = promise
                .then((res) => {
                    if (i === pFAry.length) {
                        resolve(res)
                    } else {
                        return pFAry[i](res)
                    }
                })
                .catch((error) => {
                    reject(error)
                    // 捕获错误后由于下一次循环依然会添加then,需要返回一个pending状态的promise来中断后面的所有操作
                    return new Promise(() => {})
                })
        }
    })
}

export {
    curry,
    throttle,
    countMaxDuplicateNumber,
    promiseOrder
}