JavaScript中的forEach

223 阅读1分钟

在JS中forEach在处理异步任务的时候是并行处理的:

const count = (item) => {
    return new Promise((resolve) => {
        if (typeof item === 'number') {
            setTimeout(() => {
                console.log(item);
                resolve();
            }, 500);
        } else {
            setTimeout(() => {
                console.log(item);
                resolve();
            }, 1000);
        }
    })
}

// forEach
let arr = [1, 'a', 'b', 'c', 2];
arr.forEach(async item => {
    const ret = await count(item);
});
// 1
// 2
// a
// b
// c

// for
(async function test() {
    for (let i = 0; i < arr.length; i++) {
        await count(arr[i]);
    }
})();

// for ... of
(async function test() {
    for (let x of arr) {
        const res = await count(x)
    }
})();

基于这个特性,我们可以在一些并发请求的时候使用,在手写 Promise.all 等类似方法的时候也可以使用forEach来完成。

Bromise.all = (fns) => {
  return new Bromise((resolve, reject) => {
    let count = 0;
    let res = [];
    fns.forEach((fn, index) => {
      fn.then((val) => {
        count++;
        res[index] = val;
        if (count === fns.length) {
          resolve(res);
        }
      }, (reason) => {
        reject(reason);
      });
    });
  });
}

Bromise.race = (fns) => {
  return new Bromise((resolve, reject) => {
    fns.forEach((fn) => {
      fn.then(resolve, reject);
    })
  })
}

Bromise.allSettled = (promiseList) => {
  return new Bromise((resolve, reject) => {
    const len = promiseList.length;
    let count = 0;
    let result = [];

    if (len === 0) return resolve(result);

    promiseList.forEach((promise, index) => {
      promise.then((value) => {
        count++;
        result[index] = {
          status: 'fulfilled',
          value,
        };
        if (count === len) resolve(result);
      }, (reason) => {
        count++;
        result[index] = {
          status: 'rejected',
          reason,
        };
        if (count === len) resolve(result);
      })
    })
  })
}

Bromise.any = (promiseList) => {
  const len = promiseList.length;
  let rejectArr = [];

  return new Bromise((resolve, reject) => {
    promiseList.forEach((promise, index) => {
      promise.then((res) => {
        resolve(res);
      }).catch((err) => {
        rejectArr[index] = err;
        if (rejectArr.length === len) {
          reject(new Error(rejectArr));
        }
      });
    });
  });
}