• Promise花落谁家知多少


    Promise系列导航

    1.Promise本质击鼓传花的游戏
    2.Promise四式击鼓
    3.Promise击鼓传花
    4.Promise花落谁家知多少


    前言

    👨‍💻👨‍🌾📝记录学习成果,以便温故而知新
    1. Promise系列文章时学习VUE的知识准备,所以就归为VUE系列了。根据MDN的描述,应该是“JavaScript 标准内置对象”,特此说明。
    2. Promise系列文章主要是学习MDN中 Promise的心得体会,MDN地址

    先看一下MDN的描述。

    Promise.all() MDN的说明:

    Promise.all() 静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。

    Promise.any() MDN的说明:

    Promise.any() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝。

    Promise.race() MDN的说明:

    Promise.race() 静态方法接受一个 promise 可迭代对象作为输入,并返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定。

    Promise.allSettled() MDN的说明:

    Promise.allSettled() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组。

    MDN说得很明白,四个方法都是静态方法,入参是一个 Promise 可迭代对象,返回是一个单独的 Promise。它们是 promise 并发方法。

    本专题叫“花落谁家知多少”,其中“花落谁家”是指Promise对象敲定,进一步是兑现还是拒绝;“知多少”是数量的概念,如所有都兑现,第一个拒绝,第一个对象,任何一个敲定,所有敲定这样的概念。

    一、Promise.all()

    1.语法

    Promise.all(iterable)

    参数说明:

    iterable是 一个可迭代对象,例如 Array 或 String。

    返回值:

    • 已兑现(already fulfilled),如果传入的 iterable 为空。
    • 异步兑现(asynchronously fulfilled),如果给定的 iterable 中所有的 promise 都已兑现。兑现值是一个数组,其元素顺序与传入的 promise 一致,而非按照兑现的时间顺序排列。如果传入的 iterable 是一个非空但不包含待定的(pending)promise,则返回的 promise 依然是异步兑现,而非同步兑现。
    • 异步拒绝(asynchronously rejected),如果给定的 iterable 中的任意 promise 被拒绝。拒绝原因是第一个拒绝的 promise 的拒绝原因。

    2.代码及说明

    硬道理上。

    (1)代码段

    const p1 = Promise.resolve(1);
    const p2 = 2;
    const p3 = new Promise((resolve, reject) => {
    	setTimeout(() => {
    		resolve("魏紫");
    	}, 100);
    });
    
    Promise.all([p1, p2, p3]).then((values) => {
    	console.log(values);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    运行结果:
    在这里插入图片描述

    MDN说:

    Promise.all 等待所有兑现(或第一个拒绝)的结果。

    这个说得比较中肯,比之前的长篇大论要简洁明了。

    (2)代码段

    // 所有的值都不是 Promise,因此返回的 Promise 将被兑现
    const p1 = Promise.all([1, 2, 3]);
    // 输入中唯一的 Promise 已经被兑现,因此返回的 Promise 将被兑现
    const p2 = Promise.all([4, 5, 6, Promise.resolve(7)]);
    // 一个(也是唯一的一个)输入 Promise 被拒绝,因此返回的 Promise 将被拒绝
    const p3 = Promise.all([8, 9, 10, Promise.reject(11)]);
    
    console.log(p1);
    console.log(p2);
    console.log(p3);
    
    // 使用 setTimeout,我们可以在队列为空后执行代码
    setTimeout(() => {
    	console.log("队列现在为空");
    	console.log(p1);
    	console.log(p2);
    	console.log(p3);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    运行结果:
    在这里插入图片描述

    这段代码终于有了拒绝了。

    (3)代码段

    再回到当初的代码,当初想要获取返回就是考虑到可能会一次获取多张图片。

    html2canvas(this.$refs.imgBox, {
      height: this.$refs.imgBox.scrollHeight,	
      width: this.$refs.imgBox.scrollWidth,
    }).then((canvas) => {
      canvas.toDataURL("image/png")
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    现在再模拟解决一下:

    //主调
    function test(){
    	const p1 = Promise.all([getImg(), getImg(), getImg()]);
    	console.log(p1);
    	
    	setTimeout(() => {
    		console.log("队列现在为空");
    		console.log(p1);
    	});
    }
    
    function getImg(){
    	return new Promise((resolve, reject) => {
    		setTimeout(() => { resolve("魏紫") }, 1000);
    	}).then(() => { return "image/png"; });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    运行结果:
    在这里插入图片描述
    感觉高大上了一些……

    (4)代码段

    const p1 = Promise.all([]);
    			
    console.log(p1);
    
    • 1
    • 2
    • 3

    运行结果:
    在这里插入图片描述
    很无聊地传个空数组,为的只是要看一看运行结果。

    二、Promise.any()

    1.语法

    Promise.any(iterable)

    参数说明:

    一个 promise 的可迭代对象(例如一个数组)。

    返回:

    • 已拒绝(already rejected),如果传入的 iterable 为空的话。
    • 异步兑现(asynchronously filfilled),当给定的 iterable 中的任何一个 Promise 被兑现时,返回的 Promise 就会被兑现。其兑现值是第一个兑现的 Promise 的兑现值。
    • 异步拒绝(asynchronously rejected),当给定的 iterable 中的所有 Promise 都被拒绝时。拒绝原因是一个 AggregateError,其 errors 属性包含一个拒绝原因数组。无论完成顺序如何,这些错误都是按照传入的 Promise 的顺序排序。如果传递的 iterable 是非空的,但不包含待定的 Promise,则返回的 Promise 仍然是异步拒绝的(而不是同步拒绝的)。

    2.代码及说明

    硬道理上。

    (1)代码段

    const pErr = new Promise((resolve, reject) => {
    	reject("总是失败");
    });
    
    const pSlow = new Promise((resolve, reject) => {
    	setTimeout(resolve, 500, "最终完成");
    });
    
    const pFast = new Promise((resolve, reject) => {
    	setTimeout(resolve, 100, "很快完成");
    });
    
    Promise.any([pErr, pSlow, pFast]).then((value) => {
    	console.log(value);
    	// pFast 第一个兑现
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    运行结果:
    在这里插入图片描述
    运行结果正如MDN所说:

    Promise.any() 会以第一个兑现的 Promise 来兑现,即使有 Promise 先被拒绝。

    (2)代码段

    const failure = new Promise((resolve, reject) => {
    	reject("总是失败");
    });
    
    Promise.any([failure, Promise.reject("姚黄")]).catch((err) => {
    	console.log(err);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行结果:
    在这里插入图片描述
    运行结果正如MDN所说:

    如果没有 Promise 被兑现,Promise.any() 将使用 AggregateError 进行拒绝。

    竟然是以抛异常这种激烈手段拒绝的,貌似没有找到errors属性。

    三、Promise.race()

    1.语法

    Promise.race(iterable)

    参数说明:

    iterable是一个 promise 可迭代对象(例如数组)。

    返回值:

    一个 Promise,会以 iterable 中第一个敲定的 promise 的状态异步敲定。换句话说,如果第一个敲定的 promise 被兑现,那么返回的 promise 也会被兑现;如果第一个敲定的 promise 被拒绝,那么返回的 promise 也会被拒绝。如果传入的 iterable 为空,返回的 promise 就会一直保持待定状态。如果传入的 iterable 非空但其中没有任何一个 promise 是待定状态,返回的 promise 仍会异步敲定(而不是同步敲定)。

    2.代码及说明

    硬道理上。

    (1)代码段

    function sleep(time, value, state) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
    		if (state === "兑现") {
    			return resolve(value);
    		} else {
    			return reject(new Error(value));
    		}
        }, time);
      });
    }
    
    const p1 = sleep(500, "一", "兑现");
    const p2 = sleep(100, "二", "兑现");
    
    Promise.race([p1, p2]).then((value) => {
    	console.log(value); // “二”
    	// 两个都会兑现,但 p2 更快
    });
    
    const p3 = sleep(100, "三", "兑现");
    const p4 = sleep(500, "四", "拒绝");
    
    Promise.race([p3, p4]).then(
      (value) => {
        console.log(value); // “三”
        // p3 更快,所以它兑现
      },
      (error) => {
        // 不会被调用
      }
    );
    
    const p5 = sleep(500, "五", "兑现");
    const p6 = sleep(100, "六", "拒绝");
    
    Promise.race([p5, p6]).then(
      (value) => {
        // 不会被调用
      },
      (error) => {
        console.error(error.message); // “六”
        // p6 更快,所以它拒绝
      }
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    运行结果:
    在这里插入图片描述
    运行结果正如注释所说。

    (2)代码段

    // 传入一个已经解决的 Promise 数组,以尽快触发 Promise.race。
    const resolvedPromisesArray = [Promise.resolve("魏紫1"), Promise.resolve("魏紫2")];
    
    const p = Promise.race(resolvedPromisesArray);
    // 立即打印 p 的值
    console.log(p);
    
    // 使用 setTimeout,我们可以在堆栈为空后执行代码
    setTimeout(() => {
    	console.log("堆栈现在为空");
    	console.log(p);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    运行结果:
    在这里插入图片描述
    这段代码按MDN所说是看异步性的。

    (3)代码段

    const foreverPendingPromise = Promise.race([]);
    console.log(foreverPendingPromise);
    setTimeout(() => {
    	console.log("堆栈现在为空");
    	console.log(foreverPendingPromise);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    运行结果:
    在这里插入图片描述
    很无聊地传个空数组,只为验证MDN所说:

    一个空的可迭代对象会导致返回的 Promise 一直处于待定状态。

    (4)代码段

    const foreverPendingPromise = Promise.race([]);
    const alreadyFulfilledProm = Promise.resolve(100);
    
    const arr = [foreverPendingPromise, alreadyFulfilledProm, "非 Promise 值"];
    const arr2 = [foreverPendingPromise, "非 Promise 值", Promise.resolve(100)];
    const p = Promise.race(arr);
    const p2 = Promise.race(arr2);
    
    console.log(p);
    console.log(p2);
    setTimeout(() => {
    	console.log("堆栈现在为空");
    	console.log(p);
    	console.log(p2);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    运行结果:
    在这里插入图片描述
    这段代码的各种滋味,自行体味。

    (5)代码段

    const data = Promise.race([
      fetch("/api"),
      new Promise((resolve, reject) => {
        // 5 秒后拒绝
        setTimeout(() => reject(new Error("请求超时")), 5000);
      }),
    ])
    .then((res) => res.json())
    .catch((err) => displayError(err));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这段代码倒是很有借鉴意义。

    四、Promise.allSettled()

    1.语法

    Promise.allSettled(iterable)

    参数说明:

    iterable是一个以 promise 组成的可迭代对象(例如 Array)对象。

    返回值:

    • 已兑现(already fulfilled),如果传入的 iterable 为空的话。
    • 异步兑现(asynchronously fulfill),当给定的 iterable 中所有 promise 已经敲定时(要么已兑现,要么已拒绝)。兑现的值是一个对象数组,其中的对象按照 iterable 中传递的 promise 的顺序,描述每一个 promise 的结果,无论完成顺序如何。

    2.代码及说明

    硬道理上。

    (1)代码段

    Promise.allSettled([
    	Promise.resolve(33),
    	new Promise((resolve) => setTimeout(() => resolve(66), 0)),
    	99,
    	Promise.reject(new Error("一个错误")),
    ]).then((values) => console.log(values));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    运行结果:
    在这里插入图片描述
    运行结果正如MDN所说:

    每个结果对象都有以下的属性:

    status:一个字符串,要么是 “fulfilled”,要么是 “rejected”,表示 promise 的最终状态。
    value:仅当 status 为 “fulfilled”,才存在。promise 兑现的值。
    reason:仅当 status 为 “rejected”,才存在,promsie 拒绝的原因。

    (2)代码段

    const p = Promise.allSettled([]);
    			
    console.log(p);
    
    setTimeout(() => {
    	console.log("堆栈现在为空");
    	console.log(p);
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行结果:
    在这里插入图片描述
    把无聊进行到底也是一种境界。

    总结

    到此整个Promise系列就结束了,现在给整个系列做个总结:四击、三传与四知。

  • 相关阅读:
    【高等数学】微分中值定理
    相似性搜索:第 4 部分--分层可导航小世界 (HNSW)
    mindspore训练retinanet时报错无法计算loss,停止训练
    margin塌陷和margin重合问题的解决方法总结
    Windows系统安装
    CSDN竞赛六期
    编译运行Linux内核
    AI实战营第二期 第七节 《语义分割与MMSegmentation》——笔记8
    SAP 公司代码全局参数设置及其意义
    如何在 ACK 中使用 MSE Ingress
  • 原文地址:https://blog.csdn.net/mlw519/article/details/133428912