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);
});

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

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);
});

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

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

(3)代码段

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

html2canvas(this.$refs.imgBox, {
  height: this.$refs.imgBox.scrollHeight,	
  width: this.$refs.imgBox.scrollWidth,
}).then((canvas) => {
  canvas.toDataURL("image/png")
});

现在再模拟解决一下:

//主调
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"; });
}

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

(4)代码段

const p1 = Promise.all([]);
			
console.log(p1);

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

二、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 第一个兑现
});

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

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

(2)代码段

const failure = new Promise((resolve, reject) => {
	reject("总是失败");
});

Promise.any([failure, Promise.reject("姚黄")]).catch((err) => {
	console.log(err);
});

运行结果:
在这里插入图片描述
运行结果正如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 更快,所以它拒绝
  }
);

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

(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);
});

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

(3)代码段

const foreverPendingPromise = Promise.race([]);
console.log(foreverPendingPromise);
setTimeout(() => {
	console.log("堆栈现在为空");
	console.log(foreverPendingPromise);
});

运行结果:
在这里插入图片描述
很无聊地传个空数组,只为验证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);
});

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

(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));

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

四、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));

运行结果:
在这里插入图片描述
运行结果正如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);
});

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

总结

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值