一. 带时间限制的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网友提供的思路
解决方法
首先得返回一个数组,一个是 function,一个是 Promise
其次我们要走完这个 generator 得不停的调用 next 方法。一般用 while 或者递归,这里我们涉及传参给下一个调用,所以要用递归
我们有个 cancel 方法,根据题意,这个方法显然是要用 throw 方法的,并且其失败被 generator 调用方 捕获时,要直接 reject 这个 Promise。所以要利用闭包定义在 Promise 中
generator 内部调用的 Promise 可能成功也可能失败,所以要处理成功、失败两种情况。对于这个 Promise 来说,成功的回调我们走 next,失败的回调我们应该 throw
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
*/