• Promise击鼓传花


    Promise系列导航

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


    前言

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

    本专题虽然叫“击鼓传花”,但是重点是“传花”。

    先看一下MDN的描述。

    Promise.prototype.then() MDN的说明:

    Promise 实例的 then() 方法最多接受两个参数:用于 Promise 兑现和拒绝情况的回调函数。它立即返回一个等效的 Promise 对象,允许你链接到其他 Promise 方法,从而实现链式调用。

    Promise.prototype.catch() MDN的说明:

    Promise 实例的 catch() 方法用于注册一个在 promise 被拒绝时调用的函数。它会立即返回一个等效的 Promise 对象,这可以允许你链式调用其他 promise 的方法。此方法是 Promise.prototype.then(undefined, onRejected) 的一种简写形式。

    Promise.prototype.finally() MDN的说明:

    Promise 实例的 finally() 方法用于注册一个在 promise 敲定(兑现或拒绝)时调用的函数。它会立即返回一个等效的 Promise 对象,这可以允许你链式调用其他 promise 方法。
    这可以让你避免在 promise 的 then() 和 catch() 处理器中重复编写代码。

    三个方法有个共同特征,这点MDN已经说得很清楚了,它们都是实例方法

    击鼓传花的经典代码,这次改进了一下,感觉更具可读性了:

    const promise = new Promise((resolve, reject) => {
    	console.log("开始击鼓");
    	Math.random()>0.5 ? resolve("魏紫") : reject("姚黄");
    });
    
    promise.then(Wz => { console.log(Wz); return "传" + Wz; }, 
    	Yh => { console.log(Yh); return "传" + Yh; })//调用then
    .then(passWhich => console.log(passWhich))//调用then
    .catch( e => console.log(e))//调用catch
    .finally(() => console.log("姚黄魏紫开次第,不觉成恨俱零凋"));//调用finally
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    两次运行结果:
    在这里插入图片描述
    下面依次说明一下。

    一、Promise.prototype.then()

    1.语法

    then()
    then(onFulfilled)
    then(onFulfilled, onRejected)

    因为then()是实例方法,所以它必然是被一个Promise对象调用,假定Promise对象的定义如下:

    const promise = new Promise((resolve, reject) => {
    	resolve("魏紫") || reject("姚黄");//调用resolve或reject
    })
    
    • 1
    • 2
    • 3

    先说 then(onFulfilled, onRejected)中的onFulfilled:

    如果onFulfilled是函数,那么它将是 Promise 对象被兑现时异步执行的函数。它的返回值将成为 then() 返回的 Promise 对象的兑现值。此函数被调用时将传入的参数是上述假定中的"魏紫"。
    如果 onFulfilled 不是一个函数,则内部会被替换为一个恒等函数((x) => x),它只是简单地将兑现值向前传递。

    再说 then(onFulfilled, onRejected)中的onRejected:

    如果 onRejected 是函数,那么它将是 Promise 对象被拒绝时异步执行的函数。它的返回值将成为 then() 返回的 Promise 对象的兑现值。此函数被调用时将传入的参数是上述假定中的"姚黄"。
    如果 onRejected 不是一个函数,则内部会被替换为一个抛出器函数((x) => { throw x; }),它会抛出它收到的拒绝原因。

    then(onFulfilled)是then(onFulfilled, onRejected)的特殊情况,只处理resolve(“魏紫”)。

    then()更加特殊,它等待resolve(“魏紫”)的调用,却不处理,感觉是原封不动地把“魏紫”往后传递,下面代码与运行结果应该能够说明。

    new Promise((resolve, reject) => {
    	console.log("开始击鼓");
    	resolve("魏紫");
    }).then().then().then(x => console.log(x));
    
    • 1
    • 2
    • 3
    • 4

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

    onFulfilled与onRejected回调函数的返回值,因情况而异,下面结合代码说明一下。

    2.代码及说明

    还是直接代码。

    (1)代码段:

    const p1 = new Promise((resolve, reject) => { resolve("魏紫"); });
    			
    p1.then(
      (value) => { console.log(value); },
      (reason) => { console.error(reason);}
    );
    
    const p2 = new Promise((resolve, reject) => { reject("姚黄"); });
    
    p2.then(
      (value) => { console.log(value); },
      (reason) => { console.error(reason);}
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    运行结果:
    在这里插入图片描述
    这代代码基本操作而已。

    (2)代码段:

    Promise.resolve(1).then(2).then(3).then(console.log); // 1
    Promise.reject(4).then(5, 6).then(7, 8).then(console.log, console.log); // 4
    
    • 1
    • 2

    运行结果:
    在这里插入图片描述
    这段代码传的是非函数作为参数,结果有些意外。

    (3)代码段:

    Promise.resolve("魏紫")
    .then(Wz => new Promise((resolve, reject) => {
    	setTimeout(() => { resolve("传" + Wz); }, 1000);	
    }))
    .then(Wz => { console.log("是" + Wz); return Wz; })//是新new出的对象的调用
    .then(Wz => console.log(Wz));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    运行结果:
    在这里插入图片描述
    这段代码then方法返回一个新的Promise对象,它替换原对象继续链式调用。

    (4)代码段:

    const promise = new Promise((resolve, reject) => {
    	resolve(1);
    });
    
    promise.then((Wz) => {
    	console.log(Wz); // 1
    	return Wz + 1;
    }).then((Wz) => {
    	console.log(promise);
    	console.log(Wz);
    });
    
    promise.then((Wz) => {
    	console.log(promise);
    	console.log(Wz); // 1
    });
    
    console.log(promise);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    运行结果:
    在这里插入图片描述
    这段代码Promise对象调用了2次then方法,onFulfilled回调函数的传参都是一样的。

    (5)代码段:

    Promise.resolve()
    .then(() => {
    	// 令 .then() 返回一个被拒绝的 promise
    	throw new Error("俱零凋");
    })
    .then(
    	() => {
    		console.log("不会被调用。");
    	},
    	(error) => {
    		console.error(`onRejected 函数被调用:${error.message}`);
    	}
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    运行结果:
    在这里插入图片描述
    这段代码then方法抛出了异常,被链式调用then方法的onRejected回调给处理。

    (6)代码段:

    Promise.resolve()
    .then()
    .then(
    	() => "魏紫",
    	() => "姚黄",
    )
    .then()
    .then((solution) => console.log(`兑现为:${solution}`));
    
    Promise.reject()
    .then()
    .then(
    	() => "魏紫",
    	() => "姚黄",
    )
    .then()
    .then((solution) => console.log(`兑现为:${solution}`));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    运行结果
    在这里插入图片描述
    这段代码运行结果很有意思,可以(3)代码段结合着看。

    (7)代码段:

    当初的问题如何返回:

    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(){
    	console.log(saveImg());
    }
    
    async function saveImg(){
    	const img = await getImg();
    	console.log(img);
    	return img;
    }
    
    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

    运行结果:
    在这里插入图片描述
    运行结果表名主调函数test()中返回的是Promise对象,而saveImg()中由于加了await关键字,所以能输出then方法中的返回。

    二、Promise.prototype.catch()

    1.语法

    catch(onRejected)

    onRejected是回调函数,MDN说:

    一个在此Promise对象被拒绝时异步执行的函数。它的返回值将成为 catch() 返回的 Promise 对象的兑现值。此函数被调用时将传入参数是Promise对象的拒绝值。

    以下代码:

    Promise.reject("姚黄").catch();
    Promise.reject("姚黄").catch(1);
    
    • 1
    • 2

    运行结果:
    在这里插入图片描述
    这结果就如同catch没有起作用一样。

    以下代码:

    Promise.reject("姚黄").catch().catch(Yh => console.log(Yh));
    Promise.reject("姚黄").catch(1).catch(Yh => console.log(Yh));
    
    • 1
    • 2

    运行结果:
    在这里插入图片描述
    说明什么呢???

    onRejected回调函数的返回值也因情况而异,还是结合代码说一下。

    2.代码及说明

    代码是硬道理。

    (1)代码段:

    const p1 = new Promise((resolve, reject) => {
    	resolve("成功!");
    });
    
    p1.then((value) => {
    	console.log(value); // "成功!"
    	throw new Error("姚黄1");
    })
    .catch((e) => {
    	console.error(e.message); //
    })
    .then(
        () => console.log("在 catch 后,调用链恢复了"),
        () => console.log("因为有了 catch 而不会被触发"),
    );
    
    // 下面的行为与上面相同
    p1.then((value) => {
    	console.log(value); // "成功!"
    	return Promise.reject("姚黄2");
    })
    .catch((e) => {
    	console.error(e);
    })
    .then(
        () => console.log("在 catch 后,调用链恢复了"),
        () => console.log("因为有了 catch 而不会被触发"),
    );
    
    • 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

    运行结果:
    在这里插入图片描述
    运行结果表明catch可以抛出的异常或者拒绝,与onRejected的功能一样,正如MDN所说:

    Promise.prototype.catch()是 Promise.prototype.then(undefined, onRejected) 的一种简写形式。

    (2)代码段:

    const p1 = new Promise((resolve, reject) => {
    	throw new Error("姚黄");
    });
    
    p1.catch((e) => {
    	console.error(e);
    });
    
    console.log(p1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

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

    大多数情况下,抛出错误会调用 catch() 方法

    但是console.log(p1)的输出应该是能说明一点问题的。

    (3)代码段:

    const p2 = new Promise((resolve, reject) => {
    	setTimeout(() => {
    		throw new Error("未捕获的异常!");
    	}, 1000);
    });
    
    p2.catch((e) => {
    	console.error(e); // 永远不会被调用
    });
    
    console.log(p2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

    在异步函数内部抛出的错误会像未捕获的错误一样。

    这里console.log(p2)的输出应该是能说明一些问题的。

    (4)代码段:

    const p3 = new Promise((resolve, reject) => {
    	resolve();
    	throw new Error("Silenced Exception!");
    });
    
    p3.catch((e) => {
    	console.error(e); // 这里永远不会执行
    });
    
    console.log(p3);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

    在调用 resolve 之后抛出的错误会被忽略。

    这里感觉MDN并没有说清楚,resolve或reject的调用有退出函数调用栈的功能。

    (5)代码段

    Promise.resolve("魏紫")
    .catch(reason => console.log("执行catch:" + reason))
    .then(Wz => console.log("onFulfilled:" + Wz), 
    	Yh => console.log("onRejected:" + Yh));
    
    • 1
    • 2
    • 3
    • 4

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

    运行结果说明不该catch管的事,人坚决不管,并且还不影响链式调用。

    Promise.reject("姚黄")
    .catch(reason => { console.log("执行catch:" + reason); return reason; })
    .then(Wz => console.log("onFulfilled:" + Wz),
    	Yh => console.log("onRejected:" + Yh));
    
    • 1
    • 2
    • 3
    • 4

    运行结果:
    在这里插入图片描述
    运行结果说明该catch管的事,绝不含糊,并且使链式调用继续下去。

    三、Promise.prototype.finally()

    1.语法

    finally(onFinally)

    onFinally是回调函数,MDN说:

    onFinally是一个当 promise 敲定时异步执行的函数。它的返回值将被忽略,除非返回一个被拒绝的 promise。调用该函数时不带任何参数。

    如下代码:

    Promise.resolve("魏紫1").finally().then(console.log);
    Promise.resolve("魏紫2").finally(1).then(console.log);
    
    • 1
    • 2

    运行结果:
    在这里插入图片描述
    运行结果说明,onFinally可以不传,或者传常数也不报错,照常运行。

    onFinally 回调函数不接收任何参数,MDN说:

    这种情况恰好适用于你不关心拒绝原因或兑现值的情况,因此无需提供它。

    2.代码及说明

    还是上硬道理。

    (1)代码段

    const p1 = Promise.resolve(1).then(() => 5, () => {});
    const p2 = Promise.resolve(2).finally(() => 6);
    const p3 = Promise.reject(3).then(() => {}, () => 7);
    const p4 = Promise.reject(4).finally(() => 8);
    
    console.log(p1);
    console.log(p2);
    console.log(p3);
    console.log(p4);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

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

    以上代码根据MDN说明“onFinally调用通常是透明的,不会更改原始 promise 的状态”改的,个中滋味,请自我品味。

    (2)代码段

    const p1 = Promise.reject(1).finally(() => { throw 3; });
    const p2 = Promise.reject(2).finally(() => Promise.reject(4));
    
    console.log(p1);
    console.log(p2);
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    在 finally 回调函数中抛出错误(或返回被拒绝的 promise)仍会导致返回的 promise 被拒绝。

    一般来说到Promise.prototype.finally()就结束了,这里的2段代码只是为了验证MDN所说。

  • 相关阅读:
    北斗GPS卫星时钟同步服务器在银行数据机房应用
    全新升级的AOP框架Dora.Interception[3]: 基于特性标注的拦截器注册方式
    大型网站高并发解决方案——集群
    .NET MAUI 安卓应用开发初体验
    Nature工作-通用时序(PHM)大模型//(构思中)
    计算机组成原理--存储系统
    阿里云OSS对象存储
    K8S:K8S自动化运维容器Docker集群
    系统开发视角下的诊断 ———— 网络通信(U)诊断故障2
    Seaborn 回归(Regression)及矩阵(Matrix)绘图
  • 原文地址:https://blog.csdn.net/mlw519/article/details/133428734