有时间限制的promise对象

457 阅读2分钟

前言:锻炼自己的思想,规范自己的编程思路。

问题:请你编写一个函数,它接收一个异步函数 fn 和一个以毫秒为单位的时间 t。它应根据限时函数返回一个有 限时 效果的函数。

限时函数是与原函数相同的函数,除非它需要 t 毫秒以上的时间来完成。如果出现了这种情况,请你返回 "Time Limit Exceeded" 拒绝这次函数的调用。注意,它应该返回一个字符串拒绝,而不是一个 Error 。

示例:(放代码里面)

输入:
fn = async (n) => { 
  await new Promise(res => setTimeout(res, 100)); 
  return n * n; 
}
inputs = [5]
t = 50
输出:{"rejected":"Time Limit Exceeded","time":50}
解释:
提供的函数设置在 100ms 后执行完成,但是设置的超时时间为 50ms,所以在 t=50ms 时拒绝因为达到了超时时间。

思路:这个题目可以使用 Promise.race 方法。Promise.race 方法接收一个可迭代对象,它返回一个新的 Promise 对象,该对象在可迭代对象中的任何一个 Promise 对象被解决或拒绝时解决或拒绝。

因此,我们可以创建一个超时 Promise,它在给定的超时时间后被拒绝,并使用 Promise.race 来比较原始函数的执行时间和超时时间。如果原始函数在超时时间内完成,则返回其结果;否则,返回 “Time Limit Exceeded”。

基于上述思考,代码如下:

/**
 * @param {Function} fn
 * @param {number} t
 * @return {Function}
 */
var timeLimit = function withTimeout(fn, t) {
  return async function(...args) {
    const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject('Time Limit Exceeded'), t));
    return Promise.race([fn(...args), timeoutPromise]);
  }
}

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

执行结果如下图:

image-20230602232547643.png

结论:这个函数返回一个新的异步函数,它使用 Promise.race 来比较原始函数的执行时间和超时时间。如果原始函数在超时时间内完成,则返回其结果;否则,返回 “Time Limit Exceeded”。