复习JS基础之带时间限制的Promise、带取消功能的Promise、嵌套数组生成器

117 阅读2分钟

一. 带时间限制的Promise

思路

利用setTimeout函数进行延迟t毫秒时间,到了这个时候promise还没返回就直接reject

解决方法

定义一个变量用于记录是否已经超时,超时的话,后面在执行fn函数时,在resolve时无需调用resolve函数进行返回了,可直接参考下面的实现

实现

/**
 * @param {Function} fn
 * @param {number} t
 * @return {Function}
 */
var timeLimit = function(fn, t) {
	return async function(...args) {
        return new Promise((resolve, reject) => {
            let isRejected = false;
            setTimeout(function () {
                isRejected = true;
                reject('Time Limit Exceeded');
            }, t);
            fn(...args).then((...response) => isRejected || resolve(...response), reject);
        });
    }
};

/**
 * const limited = timeLimit((t) => new Promise(res => setTimeout(res, t)), 100);
 * limited(150).catch(console.log) // "Time Limit Exceeded" at t=100ms
 */

二. 设计可取消函数

思路

通过生成器的throw方法,来模拟取消

这里的思路和实现参考leetcode网友提供的思路

思路链接:leetcode.cn/problems/de…

解决方法

  1. 首先得返回一个数组,一个是 function,一个是 Promise

  2. 其次我们要走完这个 generator 得不停的调用 next 方法。一般用 while 或者递归,这里我们涉及传参给下一个调用,所以要用递归

  3. 我们有个 cancel 方法,根据题意,这个方法显然是要用 throw 方法的,并且其失败被 generator 调用方 捕获时,要直接 reject 这个 Promise。所以要利用闭包定义在 Promise 中

  4. generator 内部调用的 Promise 可能成功也可能失败,所以要处理成功、失败两种情况。对于这个 Promise 来说,成功的回调我们走 next,失败的回调我们应该 throw

  5. generator 本身会抛出一个错误,所以要对 next 的运行进行 try catch,根据题意 catch 后我们要直接 reject 掉这个 Promise

实现

/**
 * @param {Generator} generator
 * @return {[Function, Promise]}
 */
var cancellable = function(generator) {
    let cancel = function () {
        
    }
    const p = new Promise((resolve, reject) => {
        cancel = (msg = 'Cancelled') => {
            execute(msg, 'throw');
        };
        function execute(msg, fnName = 'next') {
            try {
                const { value, done } = generator[fnName](msg);
                if (done) {
                    resolve(value);
                    return;
                }
                value.then(val => {
                    execute(val);
                }).catch(err => {
                    execute(err, 'throw');
                });
            } catch(err) {
                reject(err);
            }
        }
        execute(null);
    });
    return [cancel, p];
};

/**
 * function* tasks() {
 *   const val = yield new Promise(resolve => resolve(2 + 2));
 *   yield new Promise(resolve => setTimeout(resolve, 100));
 *   return val + 1;
 * }
 * const [cancel, promise] = cancellable(tasks());
 * setTimeout(cancel, 50);
 * promise.catch(console.log); // logs "Cancelled" at t=50ms
 */

三、嵌套数组生成器

思路

将嵌套的多维数组拍平,之后在进行循环执行

解决方法

将嵌套的多维数组拍平,之后在进行循环执行

实现

方案1

/**
 * @param {Array} arr
 * @return {Generator}
 */
var inorderTraversal = function*(arr) {
    arr = arr.flat(Infinity);
    for (const item of arr) {
       yield item;
    }
};

/**
 * const gen = inorderTraversal([1, [2, 3]]);
 * gen.next().value; // 1
 * gen.next().value; // 2
 * gen.next().value; // 3
 */

方案2

/**
 * @param {Array} arr
 * @return {Generator}
 */
var inorderTraversal = function*(arr) {
    let context = {
        prev: null,
        arr,
        index: 0,
    };
    while(true) {
        const value = context.arr[context.index];
        if (value !== null && typeof value === 'object') {
            const prev = context;
            context = {
                prev,
                arr: value,
                index: 0
            }
        } else if (typeof value === 'number') {
            yield value;
            context.index ++;
        } else {
            context = context.prev;
            if (!context) {
                break;
            }
            context.index += 1;
        }
    }
};

/**
 * const gen = inorderTraversal([1, [2, 3]]);
 * gen.next().value; // 1
 * gen.next().value; // 2
 * gen.next().value; // 3
 */