关于Promise 面试的那些问题

66 阅读2分钟
js请求取消

mp.weixin.qq.com/s/BVSwRL1bX…

取消本质是取消返回处理

1. Promise 超时重试

题目补充:
实现一个函数 retryWithTimeout,接收一个返回 Promise 的函数 fn,一个超时时间 timeout 和最大重试次数 retries,在失败或超时的情况下自动重试,直到成功或达到最大重试次数。

function retryWithTimeout(fn, timeout, retries) {
  const tryOnce = () => {
    return Promise.race([
      fn(),
      new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), timeout))
    ]);
  };

  return new Promise((resolve, reject) => {
    const attempt = (n) => {
      tryOnce().then(resolve).catch(err => {
        if (n <= 0) {
          reject(err);
        } else {
          attempt(n - 1);
        }
      });
    };
    attempt(retries);
  });
}

2. 多个 Promise 顺序输出结果

给定一个异步函数数组 tasks(每个函数返回一个 Promise),请按顺序执行并输出每个 Promise 的结果,保证顺序一致。

const tasks = [
  () => Promise.resolve(1),
  () => new Promise(resolve => setTimeout(() => resolve(2), 100)),
  () => Promise.resolve(3),
];

async function runSequentially(tasks) {
  for (const task of tasks) {
    const result = await task();
    console.log(result);
  }
}

输出顺序:123

3 并发控制

//并发控制
class ConconrencyControll {
  constructor(task, limit, cb) {
    this.task = task.slice();
    this.limit = limit
    this.cb = cb
    this.quene = new Set() // 任务队列
  }

  runTask() {
    if (this.task.length === 0) return
    while (this.quene.length < this.limit) {
      let task = this.task.shift()
      this.quene.set(task)
      task().finally(() => {
        this.quene.delete(task)
        if (this.quene.length === 0) {
          this.cb()
        } else {
          this.runTask()
        }
      })
    }
  }

  addTask(task) {
    this.task.push(task)
    this.runTask()
  }
}

4 手写promise 函数

  • new Promise((resolve,reject)=>{})

  • 记录state 状态 value 成功值 reason 失败值

  • resove调用,状态变更fulfilled,reject调用,状态变更rejected

  • then 回调 根据状态不同,调用onFullfilled,onRejected ,可能异步调用resove,reject,需要发布订阅模式,先收集then的回调

  • 链式调用then的本质,then返回promise,将上一个then的结果,给返回的promise处理

  • 实现一个简单的promise

  • 一个简单的 Promise 的粗糙实现,关键点在于

  • 当 pending 时, thenable 函数由一个队列维护

  • 当状态变为 resolved(fulfilled) 时,队列中所有 thenable 函数执行

  • 当 resolved 时, thenable 函数直接执行

  • rejected 状态同理

const PEDDING = 'pedding'
const FULFILLED = "fulfilled"
const REJECT = "reject"
//
const handlePromise = (p2, x, resolve, reject){
  if (p2 === x) {
    //报错
    return reject(new TypeError("Chaining cycle detected for promise"));
  }
  if (x !== null && (typeof x === "object" || typeof x === "function")) {
    try {
      const then = x.then
      let called
      if (typeof then === "function") {
        then.call(
          x,
          y => { if (called) return; called = true; handlePromise(p2, y, resolve, reject) },
          (reseason) => {
            if (called) return;
            called = true;
            reject(reason);
          }
        )
      } else {
        resolve(x)
      }
    } catch (error) {
      reject(error);
    }
  } else {
    resolve(x)
  }
}
class SimplePromise {
  constructor(exector) {
    this.value = undefined
    this.state = PEDDING
    this.reason = undefined
    this.onFulfilledCallback = []
    this.onRejectedCallback = []
    const resolve = (value) => {
      if (this.state === PEDDING) {
        this.value = value
        this.state = FULFILLED
        this.onFulfilledCallback.forEach((cb) => cb())
      }
    }
    const reject = (reason) => {
      if (this.state === PEDDING) {
        this.reason = reason
        this.state = REJECT
        this.onRejectedCallback.forEach((cb) => cb())
      }
    }
    try {
      exector(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => value
    onRejected = typeof onRejected === "function" ? onRejected : (reason) => reason
    let p2 = new SimplePromise((resolve, reject) => {
      if (this.state === FULFILLED) {
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value)
            handlePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })

      }
      if (this.state === REJECT) {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason)
            handlePromise(p2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })

      }
      if (this.state === PEDDING) {
        setTimeout(() => {
          this.onFulfilledCallback(() => {
            try {
              let x = onFulfilled(this.value)
              handlePromise(p2, x, resolve, reject)
            } catch (error) {
              reject(error)
            }
          })
        })
        setTimeout(() => {
          this.onRejectedCallback(() => {
            try {
              let x = onRejected(this.reason)
              handlePromise(p2, x, resolve, reject)
            } catch (error) {
              reject(error)
            }
          })
        })
      }
    })
    return p2
  }
}


Promise.resolve = (value) => {
  return new Promise((resolve) => {
    resolve(value);
  });
};

Promise.reject = (value) => {
  return new Promise((resolve, reject) => {
    reject(value);
  });
};

Promise.myAll = (promises) => {
  return new Promise((rs, rj) => {
    let count = 0
    let result = []
    const len = promises.length

    if (len === 0) {
      return resolve([])
    }

    promises.forEach((p, i) => {
      Promise.resolve(p).then((res) => {
        count += 1
        result[ i ] = res
        
        if (count === len) {
          rs(result)
        }
      }).catch(rj)
    })
  })
}


function race(arr){
  return new Promise((res,rej) => {
    for(let i = 0; i < arr.length; i++){
      arr[i].then(resolve => {
        res(resolve)  //某一promise完成后直接返回其值
      }).catch(e => {
        rej(e)  //如果有错误则直接结束循环,并返回错误
      })
    }
  })
}