第七节JavaScript Promise

一、JavaScript Promise

1、简介

Promise是一个ES6提供的类,目的是更加优雅地书写复杂的异步任务。

由于Promise是ES6新增的,所以一些旧的浏览器并不支持,苹果的Safari 10和Windows的Edge 14版本以上的浏览器才支持,这个需要注意。

2、构造Promise

新构建第一个Promise对象:
     new Promise(function(resolve, reject) {

// 处理的逻辑

});

    通过新建一个Promise对象好像并没有看出它怎么实现“更加优雅地书写复杂的异步任务”。接下来,我们通过需要多次调用异步函数来看下:

普通方式:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Javascript基础学习</title>
	</head>
	<body>
		<h2>JavaScript Promise</h2>
		<button onclick="yibu()">异步</button>
		<p id="one"></p>
		<p id="two"></p>
		<p id="three"></p>
	</body>

	<script>
		function yibu() {
			setTimeout(function() {
				document.getElementById("one").innerHTML = "3000ms -- First";
				console.log("First");
				setTimeout(function() {
				    document.getElementById("two").innerHTML = "4000ms -- Second";
					console.log("Second");
					setTimeout(function() {
				        document.getElementById("three").innerHTML = "1000ms -- Third";
						console.log("Third");
					}, 3000);
				}, 4000);
			}, 1000);
		}
	</script>
</html>

输出结果:

从上面也能看出,这种“函数瀑布”实现的无论是维护还是异常处理都是特别繁琐的事情,而且也会让缩进格式变得冗赘。

下面我们用Promise来实现同样的功能:

代码:

<script>
		function yibu() {
			new Promise(function(resolve, reject) {
				setTimeout(function() {
					document.getElementById("one").innerHTML = "3000ms -- First";
					console.log("First");
					resolve();
				}, 3000);

			}).then(function() {
				return new Promise(function(resolve, reject) {
					setTimeout(function() {
						document.getElementById("two").innerHTML = "4000ms -- Second";
						console.log("Second");
						resolve();
					}, 4000);
				});

			}).then(function() {
				setTimeout(function() {
					document.getElementById("three").innerHTML = "1000ms -- Third";
					console.log("Third");
				}, 1000);
			});
		}
	</script>

输出结果:

这段代码也是很长的,现在我们不需要完全理解它,代码引起我们注意的是Promise将嵌套格式的代码变成了顺序格式的代码。

3、Promise 的构造函数

Promise构造函数是JavaScript中用于创建Promise对象的内置构造函数。

Promise构造函数接受一个函数作为参数,该函数是同步的并且立即执行,所以我们称之为起始函数。起始函数包含两个参数 resolve和reject,分别表示Promise成功和失败的状态

起始函数执行成功时,它应该调用resolve函数并传递成功的结果。当起始函数执行失败时,它应该调用reject函数并传递失败的原因。

Promise构造函数返回一个Promise对象,该对象具有以下几个方法:

  • then:用于处理Promise成功状态的回调函数
  • catch:用于处理Promise失败状态的回调函数
  • finally:无论Promise是成功还是失败,都会执行的回到函数。

        下面实例是使用Promise构造含税创建Promise对象(当Promise被构造时,起始函数会被同步执行):

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Javascript基础学习</title>
	</head>
	<body>
		<h2>JavaScript Promise</h2>
		<button onclick="yibu()">异步</button>
		<p id="one"></p>
		<p id="two"></p>
		<p id="three"></p>
	</body>

	<script>
		function yibu() {
			const prpmise01 = new Promise(function(resolve, reject) {
				setTimeout(function() {
					document.getElementById("one").innerHTML = "3000ms -- First";
					console.log("First");
					resolve("success First");
				}, 3000);

			})

			prpmise01.then(function(result) {
				document.getElementById("two").innerHTML = result;
			})
			
			const prpmise02 = new Promise(function(resolve, reject) {
				setTimeout(function() {
					console.log("prpmise02");
					reject("error three First");
				}, 3000);
			
			})
			
			prpmise02.catch(function(error) {
				document.getElementById("three").innerHTML = error;
			})
		}
	</script>
</html>

输入结果:

        在上面例子中,我们使用Promise构造函数创建了两个Promise对象,并使用setTimeout模拟一个异步场景。第一个异步操作成功,则会调用resolve函数并传递成功的结果;第二个异步场景失败,则调用reject函数并传递失败的原因。然后,我们使用then方法处理Promise成功状态的回调函数,使用catch方法处理Promise失败状态的回调函数。

接下来我们再看个小示例:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Javascript基础学习</title>
	</head>
	<body>
		<h2>JavaScript Promise</h2>
		<button onclick="yibu()">计算(a / b 或 a / c)</button>
		<p id="one"></p>
		<p id="two"></p>
	</body>

	<script>
		function yibu() {
			new Promise(function(resolve, reject) {
				var a = 4;
				var b = 2;
				if (b == 0) {
					reject("a / b The denominator cannot be zero")
				} else {
					var value = a / b;
					resolve(value);
				}
			}).then(function(result) {
				document.getElementById("one").innerHTML = "a / b = " + result;
			}).catch(function(error) {
				document.getElementById("two").innerHTML = "a / c error = " + error;
			})

			new Promise(function(resolve, reject) {
				var a = 4;
				var c = 0;
				if (c == 0) {
					reject("a / c - The denominator cannot be zero")
				} else {
					var value = a / c;
					resolve(value);
				}
			}).then(function(result) {
				document.getElementById("one").innerHTML = "a / c = " + result;
			}).catch(function(error) {
				document.getElementById("two").innerHTML = "a / c error = " + error;
			}).finally(function(){
			document.getElementById("three").innerHTML = "End";
			})
		}
	</script>
</html>

输出结果:

        说明:Promise类有.then()、.catch()和.finally()三个方法,这三个方法的参数都是一个函数,.then()可以将参数中的函数添加到当前Promise的正常执行序列,.catch()则是设定的异常处理序列,.finally()是在Promise执行的最后一定会执行的序列。.then()传入的函数会按照顺序依次执行,在有任何异常都会直接跳转到catch序列。

例如:

resolve()中可以放置一个参数,用于向下一个then传递一个值,then中的函数也可以返回一个值传递给then。但是,如果 then 中返回的是一个 Promise 对象,那么下一个 then 将相当于对这个返回的 Promise 进行操作,这一点从刚才的计时器的例子中可以看出来。

reject() 参数中一般会传递一个异常给之后的 catch 函数用于处理异常。

注意:

  • resolve和reject的作用域只有起始函数,不包括then以及其他序列。
  • resolve和reject并不能够使起始函数停止运行,别忘了return。

4、Promise 函数

上述使用计时器实现时,代码还是很长的,所以我们可以将核心代码写成一个Promise函数:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Javascript基础学习</title>
	</head>
	<body>
		<h2>JavaScript Promise</h2>
		<button onclick="yibu()">Promise函数</button>
		<p id="one"></p>
		<p id="two"></p>
		<p id="three"></p>
	</body>

	<script>
		// 实现一个Promise函数
		function myPromise(delay, msg, pID) {
			return new Promise(function(resolve, reject) {
				setTimeout(function() {
					console.log(msg);
					document.getElementById(pID).innerHTML = msg;
					resolve();
				}, delay);
			});
		}

		function yibu() {
			myPromise(4000, "4000ms First", "one").then(function() {
				return myPromise(2000, "200ms Second", "two");
			}).then(function() {
				myPromise(2000, "end", "three");
			});
		}
	</script>
</html>

输出结果:

这种返回值为一个 Promise 对象的函数称作 Promise 函数,它常常用于开发基于异步操作的库。

5、常见的问题(FAQ)

Q: then、catch 和 finally 序列能否顺序颠倒?

A: 可以,效果完全一样。但不建议这样做,最好按 then-catch-finally 的顺序编写程序。

Q: 除了 then 块以外,其它两种块能否多次使用?

A: 可以,finally 与 then 一样会按顺序执行,但是 catch 块只会执行第一个,除非 catch 块里有异常。所以最好只安排一个 catch 和 finally 块。

Q: then 块如何中断?

A: then 块默认会向下顺序执行,return 是不能中断的,可以通过 throw 来跳转至 catch 实现中断。

Q: 什么时候适合用 Promise 而不是传统回调函数?

A: 当需要多次顺序执行异步操作的时候,例如,如果想通过异步方法先后检测用户名和密码,需要先异步检测用户名,然后再异步检测密码的情况下就很适合 Promise。

Q: Promise 是一种将异步转换为同步的方法吗?

A: 完全不是。Promise 只不过是一种更良好的编程风格。

Q: 什么时候我们需要再写一个 then 而不是在当前的 then 接着编程?

A: 当你又需要调用一个异步任务的时候。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/254997.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[AutoSar]基础部分 RTE 02 S/R Port 显式/隐式

目录 关键词平台说明一、显式&#xff08;Explicit&#xff09;和隐式&#xff08;Implicit&#xff09;1.1 显式模式1.1.1code 二、隐式模式2.1 code 三、区别 关键词 嵌入式、C语言、autosar、EcuM、Rte 平台说明 项目ValueOSautosar OSautosar厂商vector芯片厂商TI编程语…

Content-Type是什么

目录 Content-Type是什么 获取方式 设置方式 常见类型 application/x-www-form-urlencoded multipart/form-data application/json text/xml text/html text/plain Content-Type是什么 Content-Type出现在请求标头和响应标头中&#xff0c;意思是内容类型&#xff0…

Ubuntu如何安装KVM

环境&#xff1a; 联想E14笔记本 Ubuntu20.04 问题描述&#xff1a; Ubuntu如何安装KVM 解决方案&#xff1a; 1.验证CPU是否支持硬件虚拟化 rootst-ThinkPad-E14:~# grep -Eoc (vmx|svm) /proc/cpuinfo 162.检查 VT 是否在 BIOS 中启用 安装 apt install cpu-checker …

论文阅读——Painter

Images Speak in Images: A Generalist Painter for In-Context Visual Learning GitHub - baaivision/Painter: Painter & SegGPT Series: Vision Foundation Models from BAAI 可以做什么&#xff1a; 输入和输出都是图片&#xff0c;并且不同人物输出的图片格式相同&a…

隐私计算介绍

这里只对隐私计算做一些概念性的浅显介绍&#xff0c;作为入门了解即可 目录 隐私计算概述隐私计算概念隐私计算背景国外各个国家和地区纷纷出台了围绕数据使用和保护的公共政策国内近年来也出台了数据安全、隐私和使用相关的政策法规 隐私计算技术发展 隐私计算技术安全多方计…

滴滴出行:驾龄不到一年有什么办法注册网约车?

驾龄不到一年有什么办法注册网约车&#xff1f;怎么解决网约车注册审核问题。我可以为您提供一些对于如何注册滴滴快车的信息。要注册为滴滴快车司机&#xff0c;你需要符合下列规范&#xff1a; 1.年龄在12-60岁左右&#xff0c;有C1或以上驾照&#xff0c;如果驾龄不够三年是…

JVM 垃圾回收详解

前言 什么是垃圾? 垃圾是指运行程序中没有任何引用指向的对象&#xff0c;需要被回收。 内存溢出和内存泄漏 内存溢出&#xff1a;经过垃圾回收之后&#xff0c;内存仍旧无法存储新创建的对象&#xff0c;内存不够溢出。 内存泄漏&#xff1a;又叫“存储泄漏”&#xff0…

【Leetcode】旋转矩阵

题目链接&#xff1a;https://leetcode.cn/problems/rotate-matrix-lcci/description/ 题目描述 给你一幅由 N N 矩阵表示的图像&#xff0c;其中每个像素的大小为 4 字节。请你设计一种算法&#xff0c;将图像旋转 90 度。 不占用额外内存空间能否做到&#xff1f; 示例 …

cefsharp120.1.8(cef120.1.8,Chromium120.0.6099.109)版本升级测试,其他版本H264版本

此版本最新版cef120.1.8,Chromium120.0.6099.109 此更新包括一个高优先级安全更新 This update includes a high priority security update. 说明&#xff1a;本版本暂时不支持264&#xff0c;其他H264版本参考119,116&#xff0c;114&#xff0c;110&#xff0c;109等版本 c…

mysql innodb知识记录

官方文档 官网架构图 innodb 特性 内存 buffer pool 采用优化后的LRU算法&#xff0c; 3/8 of the buffer pool is devoted to the old sublist.The midpoint of the list is the boundary where the tail of the new sublist meets the head of the old sublist.When In…

地牢边缘 DUNGEON LIMBUS中文免安装版

​《地牢边缘》是一款点阵图形式的像素风经典迷宫探索类游戏。玩家需要在游戏中收集多种装备&#xff0c;随机生成的无限地下城。在生死之际遇见的迷之铁匠和管理复活之村的年轻女性。为了找回遗失的记忆&#xff0c;进入更深的地下城。玩家还可以发展村落以及进化武器的多样化…

亚信安慧AntDB数据库助力智慧高速建设

随着新型智慧交通业务的迅速发展&#xff0c;各地高速公路在管控、收费和监测方面的数据管理变得至关重要。智慧公路信息化建设已成为高速公路建设的核心。AntDB数据库在某省级客户中发挥关键作用&#xff0c;帮助构建协同共享、高效的统一智慧管理平台&#xff0c;为高速公路的…

javascript 数组处理的两个利器: `forEach` 和 `map`(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

【AI基础设施】智算场景的资源管理系统与未来展望

高性能计算与智算场景 首先澄清两个概念&#xff0c;高性能计算与智算场景&#xff0c;高性能计算主要是面向天气预测、生物计算、材料计算等场景&#xff0c;而最近几年很火的智算主要是面向AI场景的计算&#xff0c;如语音识别、图像识别、自动驾驶等场景&#xff0c;我们可…

算法学习——栈与队列

栈与队列 栈与队列理论基础用栈实现队列思路代码 用队列实现栈思路代码 删除字符串中的所有相邻重复项思路代码 有效的括号思路代码 逆波兰表达式求值思路代码 滑动窗口最大值思路代码未完待续 前 K 个高频元素思路代码拓展 总结栈在系统中的应用括号匹配问题字符串去重问题逆波…

Linux常用网络指令

网络参数设定使用的指令 手动/自动设定与启动/关闭 IP 参数&#xff1a;ifconfig, ifup, ifdown ifconfig ifconfig常用于修改网络配置以及查看网络参数的指令 [rootwww ~]# ifconfig {interface} {up|down} < 观察与启动接口 [rootwww ~]# ifconfig interface {options…

6.s081操作系统Lab4: trap

文章目录 chapter 4概览4.1 CPU trap流程使用寄存器如果cpu想处理1个trap 4.2 用户态引发的trap4.2.1 uservec4.2.2 usertrap4.2.3 usertrapret和userretusertrapretuserret Lab4Backtrace (moderate)Alarm (hard) chapter 4 概览 trap的场景&#xff1a;系统调用&#xff0c…

CUDA C:线程、线程块与线程格

相关阅读 CUDA Chttps://blog.csdn.net/weixin_45791458/category_12530616.html?spm1001.2014.3001.5482 第一百篇博客&#xff0c;写点不一样的。 当核函数在主机端被调用时&#xff0c;它会被转移到设备端执行&#xff0c;此时设备会根据核函数的调用格式产生对应的线程(…

被我们忽略的HttpSession线程安全问题

1. 背景 最近在读《Java concurrency in practice》(Java并发实战)&#xff0c;其中1.4节提到了Java web的线程安全问题时有如下一段话&#xff1a; Servlets and JPSs, as well as servlet filters and objects stored in scoped containers like ServletContext and HttpSe…

第一个程序(STM32F103点灯)

点亮LED 看原理图确定控制LED的引脚看主芯片手册确定如何设置/控制引脚写程序 LED有很多种&#xff0c;像插脚的&#xff0c;贴片的。 它们长得完全不一样&#xff0c;因此我们在原理图中将它抽象出来。 嵌入式系统中&#xff0c;一个LED的电阻非常低&#xff0c;I U/R&…