js手写promise常用函数

118 阅读3分钟

resolve & reject

  1. Promise.resolve() :创建一个已解决的 Promise,返回指定的值或对象。
  2. Promise.reject() :创建一个已拒绝的 Promise,返回指定的错误或拒绝原因。
//resolve:Promise.resolve(value)是将值转为值为fulfilled状态的promise,但是如果传入的是promise,

//就原样返回

Promise.resolve = function (value) {

    if (value instanceof Promise) {

        value

    }

    return new Promise(resolve => resolve(value))

}

  


Promise.reject = function (reason) {

    return new Promise((resolve, reject) => reject(reason))

}

  

all

在一组 Promise 中,等待所有 Promise 都解决后,返回一个包含所有解决结果的数组,如果有一个 Promise 被拒绝,返回的 Promise 也会被拒绝。


Promise.all = function (arr) {

    const result = []

    if (!Array.isArray(arr)) return 'arg is not a Array'

    return new Promise((resolve, reject) => {

        arr.forEach((p, i) => {

            Promise.resolve(p).then(val => {

                result[i] = val

                if (i === arr.length - 1) {

                    resolve(result)

                }

            }, err => {

                reject(err)

            })

        })

    })

}

  
  


// console.log(Promise)

let p1 = Promise.resolve('success')

let p3 = Promise.reject('error')

// Promise.all([p1, p3]).then((result) => {

//     console.log(result)

// }).catch((err) => {

//     console.log(err)

// })

  
  

race

在一组 Promise 中,返回第一个解决或拒绝的 Promise 的结果或错误,其他 Promise 的结果会被忽略。


function race(arr) {

    return new Promise((resolve, reject) => {

        arr.forEach(p => {

            Promise.resolve(p).then(resolve, reject)

        })

    })

}

race([p1, p3]).then(result => console.log(result))




function race(arr) {

    return new Promise((resolve, reject) => {

        arr.forEach(p => {

            promise.resolve(p).then(resolve, reject)

        })

    })

}

这里有个小问题,forEach会执行所有的数组项,但race的特性是

  • 如果第一个 Promise 在解决后调用了 resolve,则整个 race 函数的 Promise 会解决,并且剩下的元素不会执行
  • 如果第一个 Promise 在解决后调用了 reject,则整个 race 函数的 Promise 会拒绝,并且剩下的元素不会执行
  • 如果第一个 Promise 没有立即解决也没有立即拒绝,而是在稍后的时间内解决或拒绝,那么在第一个 Promise 解决或拒绝之前,剩下的元素仍然可能会执行。

要在自己的 race 函数中实现 Promise.race() 的特性,我们可以在 forEach 循环中,只处理第一个解决或拒绝的 Promise,并忽略其他 Promise。一种方法是通过添加一个变量来追踪是否已经解决了某个 Promise,然后根据情况来处理。

function race(arr) {
  let resolved = false; // 用于追踪是否已经解决了 Promise

  return new Promise((resolve, reject) => {
    arr.forEach(p => {
      p.then(
        result => {
          if (!resolved) {
            resolved = true;
            resolve(result); // 第一个解决的 Promise,调用 resolve
          }
        },
        error => {
          if (!resolved) {
            resolved = true;
            reject(error); // 第一个拒绝的 Promise,调用 reject
          }
        }
      );
    });
  });
}

// 示例用法
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 1 resolved'), 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Promise 2 resolved'), 500);
});

const promise3 = new Promise((resolve, reject) => {
  setTimeout(() => reject('Promise 3 rejected'), 2000);
});

race([promise1, promise2, promise3])
  .then(result => {
    console.log('Resolved:', result); // 只会输出第一个解决的 Promise 的结果
  })
  .catch(error => {
    console.error('Rejected:', error); // 只会输出第一个拒绝的 Promise 的错误
  });

any

在一组 Promise 中,返回第一个解决的 Promise 的结果,如果所有 Promise 都被拒绝,则返回一个合并的拒绝原因。


  


Promise.any = function (arr) {

    return new Promise((resolve, reject) => {

        let completed = 0;

        arr.forEach(p => {
            Promise.resolve(p).then(resolve).catch(e => {

                completed += 1
                if (completed === arr.length) {
                    reject(new AggregateError('All promises were rejected'));
                }
            })
        })
    })
}

  

const promise1 = Promise.reject('Promise 1 rejected');

const promise2 = Promise.reject('Promise 2 resolved');

const promise3 = new Promise((resolve, reject) => {

    setTimeout(() => reject('Promise 3 rejected'), 1000);

});

Promise.any([promise1, promise2, promise3])

    .then(result => console.log('Resolved:', result))

    .catch(error => console.log('Rejected:', error));
    

并发控制


const fn = url => {
    // 实际场景这里用axios等请求库 发请求即可 也不用设置延时
    return new Promise(resolve => {
        setTimeout(() => {
            console.log('完成一个任务', url, new Date());
            resolve({ url, date: new Date() });
        }, 1000);
    })
};

function limitQueue(urls, limit) {
    // 完成任务数
    let i = 0;
    // 填充满执行队列
    for (let excuteCount = 0; excuteCount < limit; excuteCount++) {
        run();
    }
    // 执行一个任务
    function run() {
        // 构造待执行任务 当该任务完成后 如果还有待完成的任务 继续执行任务
        new Promise((resolve, reject) => {
            const url = urls[i];
            i++;
            resolve(fn(url))
        }).then(() => {
            if (i < urls.length) run()
        })
    }
};

allSettled

在一组 Promise 中,等待所有 Promise 都解决或拒绝后,返回一个包含所有 Promise 的状态(解决或拒绝)和结果的数组。

function customPromiseAllSettled(promises) {
  return new Promise(resolve => {
    const results = [];
    let completedCount = 0;

    if (promises.length === 0) {
      resolve(results);
      return;
    }

    const handleCompletion = (result, index) => {
      results[index] = result;
      completedCount++;

      if (completedCount === promises.length) {
        resolve(results);
      }
    };

    for (let i = 0; i < promises.length; i++) {
      const promise = promises[i];
      promise
        .then(value => {
          handleCompletion({ status: "fulfilled", value }, i);
        })
        .catch(reason => {
          handleCompletion({ status: "rejected", reason }, i);
        });
    }
  });
}

// 示例用法
const promise1 = Promise.resolve(1);
const promise2 = Promise.reject("Error 2");
const promise3 = new Promise(resolve => setTimeout(() => resolve(3), 1000));

customPromiseAllSettled([promise1, promise2, promise3]).then(results => {
  console.log(results);
});