面试手写第二期 Promsie相关

文章目录

  • 一. 手写实现PromiseA+规范
  • 二. Promise.all实现
  • 三. Promise.race实现
  • 四. Promise.allsettled实现
  • 六. Promise.any实现
  • 六. 如何实现 Promise.map,限制 Promise 并发数
  • 七. 实现函数 promisify,把回调函数改成 promise 形式
  • 八. 并发请求控制

一. 手写实现PromiseA+规范

class Mypromise {
  state = 'pending'; // 状态 'pending' 'fulfilled' 'rejected'
  value = undefined; // 成功后的值
  reason = undefined; //
  // 如果要是 setTimeout改变状态,就先将回调保存起来
  resolveCallbacks = []; // .then的时候 状态为pending时,存储回调
  rejectCallbacks = [];
  constructor(fn) {
    const resolveHandler = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        console.log(this.resolveCallbacks);
        // 状态初始为pending,然后变化后在这里执行 fn
        this.resolveCallbacks.forEach((fn) => fn(this.value));
      }
    };
    const rejectHandler = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.rejectCallbacks.forEach((fn) => fn(this.reason));
      }
    };

    try {
      fn(resolveHandler, rejectHandler);
    } catch (err) {
      rejectHandler(err);
    }
  }

  then(fn1, fn2) {
    fn1 = typeof fn1 === 'function' ? fn1 : (v) => v;
    fn2 = typeof fn2 === 'function' ? fn2 : (err) => err;
    // 状态还没有发生改变,存储fn1,fn2
    if (this.state === 'pending') {
      const p1 = new Mypromise((resolve, reject) => {
        // 保存函数
        // 当状态改变为fulfilled的时候,执行下面的回调
        this.resolveCallbacks.push(() => {
          try {
            const newValue = fn1(this.value);
            resolve(newValue); // p1.value
          } catch (error) {
            reject(error);
          }
        });
        this.rejectCallbacks.push(() => {
          try {
            const newRerson = fn2(this.reason);
            reject(newRerson); // p1.reason
          } catch (error) {
            reject(error);
          }
        });
      });
      return p1;
    }
    // 状态已经改变,直接执行
    if (this.state === 'fulfilled') {
      // 执行完then 返回一个新的promise
      const p1 = new Mypromise((resolve, reject) => {
        try {
          // this.value == resolve(value)里面传的值
          const newValue = fn1(this.value);
          // 返回新的值
          console.log(newValue);
          resolve(newValue);
        } catch (error) {
          reject(error);
        }
      });
      return p1;
    }

    if (this.state === 'rejected') {
      const p1 = new Mypromise((resolve, reject) => {
        try {
          const newReason = fn2(this.reason);
          reject(newReason);
        } catch (error) {
          reject(error);
        }
      });
      return p1;
    }
  }
  // .catch 是 then的语法糖
  catch(fn) {
    return this.then(null, fn);
  }
  
  finally(fn) {
    return this.then((value) => {
      return Mypromise.resolve(fn()).then(() => value)
    }, err => {
      return Mypromise.resolve(fn()).then(() => throw err)
    })
  }
}

// MyPromise的静态方法
Mypromise.resolve = function (value) {
  return new Mypromise((resolve, reject) => resolve(value));
};

Mypromise.reject = function (value) {
  return new Mypromise((resolve, reject) => reject(reason));
};

二. Promise.all实现

Mypromise.all = function (promiseList = []) {
  const p1 = new Mypromise((resolve, reject) => {
    const result = [];
    const length = promiseList.length;
    let resolveCount = 0;

    promiseList.forEach((p, index) => {
      p.then((data) => {
        result[index] = data;
        // resolveCount 必须在 then 里面做 ++
        // 不能用index
        resolveCount++;
        if (resolveCount === length) {
          resolve(result);
        }
      }).catch((err) => {
        reject(err);
      });
    });
  });
  return p1;
};

三. Promise.race实现

Mypromise.race = function (promiseList = []) {
  let resolved = false; // 标记
  const p1 = new Promise((resolve, reject) => {
    promiseList.forEach((p) => {
      p.then((data) => {
        if (!resolved) {
          resolve(data);
          resolved = true;
        }
      }).catch((err) => {
        reject(err);
      });
    });
  });
  return p1;
};

四. Promise.allsettled实现

Mypromise.allSettled = function (promiseList = []) {
  return new Promise((resolve, reject) => {
    const res = [],
      len = promiseList.length,
      count = len;
    promiseList.forEach((item, index) => {
      item
        .then(
          (res) => {
            res[index] = { status: 'fulfilled', value: res };
          },
          (error) => {
            res[index] = { status: 'rejected', value: error };
          }
        )
        .finally(() => {
          if (!--count) {
            resolve(res);
          }
        });
    });
  });
};

六. Promise.any实现

Mypromise.any = function(promiseList = []) {
  return new HYPromise((resolve, reject) => {
    const errors = [];
    let rejectedCount = 0
    promiseList.forEach((promise, index) => {
      HYPromise.resolve(promise).then(
        value => {
          resolve(value)
        },
        reason => {
          errors[index] = reason;
          rejectedCount++;
          if (rejectedCount === promiseList.length) {
            reject(new AggregateError(errors, 'All promises were rejected'))
          }
        }
      )
    })
  })
}

六. 如何实现 Promise.map,限制 Promise 并发数

pMap([1, 2, 3, 4, 5], (x) => Promise.resolve(x + 1));
pMap([Promise.resolve(1), Promise.resolve(2)], (x) => x + 1);
// 注意输出时间控制
pMap([1, 1, 1, 1, 1, 1, 1, 1], (x) => sleep(1000), { concurrency: 2 });

class Limit {
  constructor (n) {
    this.limit = n
    this.count = 0
    this.queue = []
  }

  enqueue (fn) {
    // 关键代码: fn, resolve, reject 统一管理
    return new Promise((resolve, reject) => {
      this.queue.push({ fn, resolve, reject })
    })
  }

  dequeue () {
    if (this.count < this.limit && this.queue.length) {
      // 等到 Promise 计数器小于阈值时,则出队执行
      const { fn, resolve, reject } = this.queue.shift()
      this.run(fn).then(resolve).catch(reject)
    }
  }

  // async/await 简化错误处理
  async run (fn) {
    this.count++
    // 维护一个计数器
    const value = await fn()
    this.count--
    // 执行完,看看队列有东西没
    this.dequeue()
    console.log(value);
    return value
  }

  build (fn) {
    if (this.count < this.limit) {
      // 如果没有到达阈值,直接执行
      return this.run(fn)
    } else {
      // 如果超出阈值,则先扔到队列中,等待有空闲时执行
      return this.enqueue(fn)
    }
  }
}

Promise.map = function (list, fn, { concurrency }) {
  const limit = new Limit(concurrency)
  return Promise.all(list.map(async (item) => {
    item = await item
    return limit.build(() => fn(item))
  }))
}

const array = [1, 2, 3, 4, 5];
const concurrencyLimit = 2;

const mapper = async (item) => {
  // 模拟异步操作
  await new Promise((resolve) => setTimeout(resolve, 1000));
  return item * 2;
};

Promise.map([Promise.resolve(1), Promise.resolve(2)], mapper, { concurrency: 2 })
  .then((results) => {
    console.log(results);
  })
  .catch((error) => {
    console.error(error);
  });

七. 实现函数 promisify,把回调函数改成 promise 形式

function promisify(fn) {
  return function (...args) {
    let hasCb = args.some((v) => typeof v === "function");
    if (hasCb) {
      fn(...args);
    } else {
      return new Promise((resolve, reject) => {
        fn(...args, cb);
 
        function cb(err, data) {
          if (err) {
            reject(err);
          } else {
            resolve(data);
          }
        }
      });
    }
  };
}

var func1 = function (a, b, c, callback) {
  let rst = a + b + c;
  callback(null, rst);
};

var func2 = promisify(func1);
func2(1, 2, 3).then((rst) => {
  console.log("rst", rst);
}); //输出6

八. 并发请求控制

class ConcurrencyLimiter {
  constructor(maxConcurrency) {
    this.maxConcurrency = maxConcurrency;
    this.activeRequests = 0;
    this.queue = [];
  }

  async enqueue(request) {
    await this.waitUntilAllowed();

    try {
      this.activeRequests++;
      const response = await fetch(request.url);
      console.log(`Request ${request.id} completed with response:`, response);
    } catch (error) {
      console.error(`Request ${request.id} failed with error:`, error);
    } finally {
      this.activeRequests--;
      this.processQueue();
    }
  }

  waitUntilAllowed() {
    return new Promise((resolve) => {
      if (this.activeRequests < this.maxConcurrency) {
        resolve();
      } else {
        this.queue.push(resolve);
      }
    });
  }

  processQueue() {
    if (this.queue.length > 0 && this.activeRequests < this.maxConcurrency) {
      const nextRequest = this.queue.shift();
      nextRequest();
    }
  }
}

// 创建并发器实例,最大请求数量为 5
const limiter = new ConcurrencyLimiter(5);

// 请求列表示例
const requests = [
  { id: 1, url: 'https://api.example.com/data/1' },
  { id: 2, url: 'https://api.example.com/data/2' },
  { id: 3, url: 'https://api.example.com/data/3' },
  // 更多请求...
];

// 启动所有请求
requests.forEach((request) => {
  limiter.enqueue(request);
});

function fetch(url) {
  return new Promise((resolve, reject) => {
    resolve(url)
  })
}

你可能感兴趣的:(前端高频面试题,javascript,前端,手写)