前端手写Promise.all,你不知道的多个知识点,比想象中更精彩!

Promise.all 接受一个 Promise 可迭代对象作为输入,返回一个 Promise。当所有的输入都成功时,则返回一个包含所有成功结果的数组;如果任何一个输入失败时,则返回失败结果。

本文将通过知识问答、手写实现、知识扩展几个环节,让你彻底摸透promise.all。

知识问答

1. 什么情况下可以使用Promise.all?

  • 同时发起多个一步请求,等待所有的请求完成后再做出处理
  • 多个异步任务之间相互独立,但需要等待所有的异步任务完成后再做出处理

2.Promise.all迭代参数中如果传入的不是promise对象,返回的是什么?

Promise.all会将其隐式转换为Promise对象,并将其视为已完成状态

3.Promise.all与Promise.race有什么区别?

Promise.all等待所有的Promise完成,而Promise.race只等待第一个完成的Promise。如果Promise.race中的任何一个Promise完成或失败,它将立即返回该Promise的结果或错误

4.能否手动取消Promise.all中的某个Promise?

标准的Promise API 不提供取消功能。一旦Promise开始执行,就不能被取消

5.如果Promise.all中的一个promise永远不resolve也不reject,会发生什么?

如果Promise.all中的一个Promise永远不解析(即,它是一个悬而未决的状态),那么Promise.all将永远等待,直到所有其他的Promise都完成。这可能导致应用程序挂起或超时。在这种情况下,可能需要设置超时机制来处理这种情况

手写实现Promise.all

1. 定义返回值

Promise.all 返回的结果也是一个 Promise,先自定义一个叫myAll的方法,直接返回一个promise。

/* 自定义myAll函数 */
Promise.myAll = function () {
  const promise = new Promise();
  return promise;
}

写个例子,模拟调用我们自己写的myAll方法

/* 定义几个接受参数 */
const p1 = Promise.resolve(3);
const p2 = 1337;
const p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("foo");
    }, 100);
});

/* 调用myAll函数 */
Promise.myAll([p1, p2, p3]).then((res) => {
  console.log(res);
});

扫码加入前端交流群,期待你的加入!
描述文字

2. 对空参数的处理

我们常常使用Promise.all 时,传入一个空数组作为参数,此时会直接返回成功状态,返回结果也为一个空数组。

但这里不能简单的通过判断接受参数的长度来处理这种特殊情况,因为接受的参数是一个可迭代对象,可迭代对象不只有数组一种,还包含 String 、Array、TypedArray、Map、Set 以及 NodeList 等。

如何判断可迭代对象的长度?

使用 for…of语句,for…of语句执行一个循环,该循环处理来自可迭代对象的值序列。因为可迭代对象都必须含有 @@iterator 方法

Promise.myAll = function (args) {
    // 通过下面的promise,保存一份成功和失败的方法,用于后续的使用
    let res, rej;
    const promise = new Promise((resolve, reject) => {
        res = resolve;
        rej = reject;
    });

    // 记录接受对象的数量
    let count = 0;
    // 定义返回结果
    const result = [];
    for (const iterator of args) {
        count++;
    }

    // 如果没有可迭代内容,则直接返回成功
    if (count === 0) res(result);

    return promise;
};

3. 调用每个迭代对象

  • 任何一个迭代对象失败时,则返回失败结果
  • 全部迭代成功完成时,按照迭代顺序返回一个成功结果的数组
// 记录接受对象的数量
let count = 0;
// 记录完成的数量
let fulfilledCount = 0;
// 定义返回结果
const result = [];
for (const iterator of args) {
const index = count;
    count++;
	Promise.resolve(iterator).then((data) => {
        // 把返回结果
        result[index] = data;
        fulfilledCount++;
        // 完成数量等于总数量时,返回成功结果
        if (count === fulfilledCount) res(result);
    }, rej);
}

完成代码

Promise.myAll = function (args) {
    // 通过下面的promise,保存一份成功和失败的方法,用于后续的使用
    let res, rej;
    const promise = new Promise((resolve, reject) => {
        res = resolve;
        rej = reject;
    });

    // 记录接受对象的数量
    let count = 0;
    // 记录完成的数量
    let fulfilledCount = 0;
    // 定义返回结果
    const result = [];
    for (const iterator of args) {
        const index = count;
        count++;
        Promise.resolve(iterator).then((data) => {
            // 把返回结果
            result[index] = data;
            fulfilledCount++;
            // 完成数量等于总数量时,返回成功结果
            if (count === fulfilledCount) res(result);
        }, rej);
    }

    // 如果没有可迭代内容,则直接返回成功
    if (count === 0) res(result);

    return promise;
};

const p1 = Promise.resolve(3);
const p2 = 1337;
const p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("foo");
    }, 100);
});

Promise.myAll([p1, p2, p3]).then((res) => {
    console.log(res);
});

// [ 3, 1337, 'foo' ]

知识扩展

1. 非promise对象的隐式转换

const p1 = Promise.resolve(3);
const p2 = 1337;
const p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("foo");
    }, 100);
});
const p4 = undefined;
const p5 = {};
const p6 = null;
const p7 = true;

const promiseList = [p1, p2, p3, p4, p5, p6, p7];

Promise.all(promiseList).then((res) => {
    console.log(res);
});
// [ 3, 1337, 'foo', undefined, {}, null, true ]

2. 什么是可迭代对象

在JS中,可迭代对象是指那些实现了Symbol.iterator方法的对象。

这种类型的对象允许开发者自定义遍历的行为,从而使得不仅仅是内置的数据结构(如数组、字符串)可以迭代,自定义的对象也可以遍历。

  • 实现Symbol.iterator方法:为了使一个对象成为可迭代对象,它必须实现Symbol.iterator方法。这个方法返回一个迭代器,即具有next()方法的对象。
  • 使用for…of循环:可以使用for…of循环来遍历可迭代对象。在每次迭代中,for…of会调用迭代器的next()方法,获取下一个值。
  • 自定义迭代行为:通过定义Symbol.iterator方法,开发者可以自定义迭代的行为,例如决定如何生成序列中的下一个值。
  • 内置的可迭代对象:除了自定义对象,JavaScript中的许多内置对象如数组、字符串、Map、Set等都是可迭代的。

写在最后

欢迎大家访问我的个人网站:www.dengzhanyong.com

扫码加入前端交流群,期待你的加入!
描述文字

关注我的个人公众号,不错过每一篇推送

在这里插入图片描述

  • 27
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端筱园

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值