复习JS基础之数组过滤、转换和Promise对象池

695 阅读3分钟

一. 数组过滤

思路

循环数组每一项,将数组的元素和索引传入fn函数,并执行fn,将执行fn的结果作为过滤条件

解决方法

循环数组每一项,将数组的元素和索引传入fn函数,并执行fn,将执行fn的结果作为过滤条件

实现

/**
 * @param {number[]} arr
 * @param {Function} fn
 * @return {number[]}
 */
var filter = function(arr, fn) {
    const results = [];
    arr.forEach((item, i) => {
        if (fn(arr[i], i)) {
            results.push(arr[i]);
        }
    });
    return results;
};

二. 数组转换

思路

循环数组每一项,将数组的元素和索引传入fn函数,并执行fn,将执行fn的结果作为转换项输出到对应的数组中

解决方法

循环数组每一项,将数组的元素和索引传入fn函数,并执行fn,将执行fn的结果作为转换项输出到对应的数组中

实现

/**
 * @param {number[]} arr
 * @param {Function} fn
 * @return {number[]}
 */
var map = function(arr, fn) {
    const results = [];
    arr.forEach((item, i) => {
        results.push(fn(item, i));
    });
    return results;
};

三. Promise对象池

思路

方案1. Promise实现 方案2. es6中generator生成器 方案3. 通过Promise.allSettled + Promise.race实现 。。。 这里还有其它方案,这里只列举我想到的一些方案

解决方法

方案1:

  1. 定义一个index, count变量,用于记录当前需要执行的任务索引和已经执行完成的数量

  2. 定义一个runTask函数,用来循环执行当前要执行的任务

1.1 通过count来记录已经执行完的任务数量,将其和functions.length来比较,如果相等,就说明,所有任务都已经执行完成

1.2 通过索引来判断是否还有任务执行,有的话就通过递归runTask函数,继续执行任务

  1. 通过循环来执行runTask函数,这里结束条件为i < n && i < functions.length

方案2:

  1. 通过Symbol.iterator,给functions添加一个可迭代对象

  2. 定义一个execute函数,它接受两个参数,可迭代对象和n

2.1 根据传入的n来创建一个,可迭代循环的数组

2.2 通过循环来调用迭代对象的next方法,获取迭代对象的返回,将其返回的值作为数组的每一项

2.3 通过Promise.all来接收刚创建的数组的返回值

方案3: 这里不过多赘述了,直接看下面的实现吧

实现

方案1:

/**
 * @param {Function[]} functions
 * @param {number} n
 * @return {Function}
 */
var promisePool = async function(functions, n) {
    return new Promise((resolve) => {
        if (functions.length === 0) {
            resolve();
            return;
        }
        // 当前任务索引 完成数量
        let index = 0, count = 0;
        function runTask() {
            let currentTask = functions[index];
            index ++;
            currentTask().then(res => {
                count ++;
                if (count === functions.length) {
                    resolve();
                }
                if (index < functions.length) {
                    runTask();
                }
            });
        }
        for (let i = 0; i < functions.length && i < n; i ++) {
            runTask();
        }
    });
};

/**
 * const sleep = (t) => new Promise(res => setTimeout(res, t));
 * promisePool([() => sleep(500), () => sleep(400)], 1)
 *   .then(console.log) // After 900ms
 */

方案2:

/**
 * @param {Function[]} functions
 * @param {number} n
 * @return {Function}
 */
var promisePool = async function(functions, n) {
     async function execute(iter, n) {
        const promiseArr = Array(n).fill(0).map(async () => {
            while(true) {
                const response = iter.next();
                if (response.done) break;
                await response.value();
            }
        });
        return Promise.all(promiseArr);
    }
    const iter = functions[Symbol.iterator]();
    return execute(iter, n);
};

/**
 * const sleep = (t) => new Promise(res => setTimeout(res, t));
 * promisePool([() => sleep(500), () => sleep(400)], 1)
 *   .then(console.log) // After 900ms
 */

方案3:

/**
 * @param {Function[]} functions
 * @param {number} n
 * @return {Function}
 */
var promisePool = async function(functions, n) {
    const results = [];
    const queue = new Set();
    for (const task of functions) {
        const response = task().then(res => {
            results.push(res);
            queue.delete(response);
        });
        queue.add(response);
        if (queue.size >= n) {
            await Promise.race(queue);
        }
    }
    await Promise.allSettled(queue);
    return results;
};

/**
 * const sleep = (t) => new Promise(res => setTimeout(res, t));
 * promisePool([() => sleep(500), () => sleep(400)], 1)
 *   .then(console.log) // After 900ms
 */