由回调函数、Promise到async/await的同步写法执行异步代码_前端小曾的博客-程序员资料

技术标签: node.js  笔记  es6  vue.js  reactjs  javascript  

由回调函数、Promise到async/await的同步写法执行异步代码

同步异步是前端面试中经常遇到的问题,虽然不难,但是搞清楚两者之间的关系和转换还是很重要

同步

同步是一种线性执行的方式,执行的流程不能跨越,其后的线程要阻塞等待前面线程的运行;同步可以保证顺序一致,但是容易导致阻塞,即同步是阻塞模式。

同步一般用于流程性比较强的程序,比如用户登录功能就是同步处理的,需要用户通过用户名和密码验证后才能进入系统。

最基础的JavaScript就是同步的,单线程,自上而下运行。

通俗的话说:同步就相当于是 当客户端发送请求给服务端,在等待服务端响应的请求时,客户端不做其他的事情。当服务端做完了才返回到客户端。这样的话客户端需要一直等待,导致用户体验比较差。

异步

异步是一种并行处理的方式,不必等待一个程序执行完,就可以执行其它的任务,即异步是非阻塞模式。在程序中异步处理的结果通常使用回调函数来处理结果。

异步可以解决阻塞问题,但是会改变顺序性。

通俗的话说:异步就是,当客户端发送给服务端请求时,在等待服务端响应的时候,客户端可以做其他的事情,这样节约了时间,提高了效率。

为什么会有异步

简单来说,没有异步只有同步的话,代码只能自上而下执行,若前面的代码解析时间很长,那么下面的代码就会被阻塞;而对于用户而言,阻塞就意味着"卡死",这样就导致了很差的用户体验,这时我们就需要异步来优化代码。

ES6新特性:Promise

promise 用同步的写法执行异步代码

Promise 优化了回调函数的用法,让原本需要纵向一层一层嵌套的回调函数实现了横向的调用,也就是链式调用

首先我们模拟一个异步时间,要求1s后输出hello world

function fn(){
    
    setTimeout(()=>{
    
        var call = "hello world";
   }, 1000);
}

问题来了,我们该如何输出hello world呢?


是这样吗?

function fn(){
    
     setTimeout(()=>{
    
         var call = "hello world";
    }, 1000);
	return call;
}
console.log(fn()); //Uncaught ReferenceError: call is not defined

不不不,这样会报错。这是因为setTimeout是异步执行,1s后才会执行 var call = “hello world”;这时会先执行return call;所以call is not defined


还是这样?

function fn(){
    
     setTimeout(()=>{
    
         var call = "hello world";
		 return call;
    }, 1000);
}
console.log(fn()); //undefined

不不不,这样也达不到预期效果!这是因为执行 console.log(fn()) 时,fn()没有返回值,所以undefined;而1s后再执行setTimeout


ES5:通过回调函数来处理异步执行的结果
function fn(callback){
    
     setTimeout(()=>{
    
         var call = "hello world";
		 callback(call);
    }, 1000);
}
fn(function(call){
    
	console.log(call); //hello world
});

通过回调函数,我们得到了想要的结果;但是在整体结构上,我们多了一个回调函数,这样看起来不太友好。于是,ES6的Promise诞生了!


ES6:通过Promise来处理异步执行的结果
function fn(resolve,reject){
    
     setTimeout(()=>{
    
         var call = "hello world";
		 resolve(call);
    }, 1000);
}
let p = new Promise(fn);
p.then(function(res){
    
	console.log(res); //hello world
})

Promise是同步的,它里面执行到异步任务以前都是同步执行的。当执行的异步任务的时候,就被挂起了,然后继续执行主线程Promise后面的代码。当异步任务有结果返回的时候,Promise的状态就改变啦!

Promise 构造函数接受一个函数作为参数,函数里面有两个参数 resolve 和 reject ,其中 resolve 作为执行成功的函数, reject 作为执行失败的函数

下面我们以一个小例子来讲解一下resolve和reject

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<button type="button">按钮</button>
		<script type="text/javascript">
			let oBtn = document.querySelector('button');
			//定义一个开关,通过按钮来控制开关的值是true还是false
			let Off = true; 
			oBtn.onclick = function(){
    
				function fn(resolve,reject){
    
				     setTimeout(()=>{
    
				         var call = "hello world";
						 if(Off){
    
							 Off = !(Off);
							 resolve(call);
						 }else{
    
							 Off = !(Off);
							 reject('获取失败!');
						 }
				    }, 1000);
				}
				let p = new Promise(fn);
				p.then((res) => {
    
					console.log(res);//hello world
				},(res) => {
    
					console.log(res);//获取失败!
				})
			}
		</script>
	</body>
</html>

多次点击按钮,上述代码会依次输出如图所示结果:
在这里插入图片描述


ES7新特性:async…await

1. async 将普通方法转为 异步并且返回 promise对象
2. await 将异步代码转为同步结果,等着异步代码执行完才执行后面的代码

怎么拿到异步数据?

方法一:

async 将普通方法转为 异步并且返回 promise对象

//async  将普通方法转为 异步并且返回 promise对象
async function test(){
    
	return 'goods';
}
console.log(test());//Promise {<resolved>: "goods"}
let p = test();
p.then(function(res){
    
	console.log(res); //goods
})
方法二:

await 必须在异步函数中使用

async function test(){
    
	return 'goods';
}
//await 必须在异步函数中使用
async function fn(){
    
	let data = await test(); 
	console.log(data); //goods
}
fn();

await 将异步代码转为同步结果,等着异步代码执行完才执行后面的代码

请仔细对比下面两个例子的输出!

async function fn1(){
      
	return  '成功';
}
async function fn2(){
    
	console.log(1111);
	let  p = fn1();
	p.then(function(res){
    
		console.log(res);
	});
	console.log(3333);
}
fn2();
/**
输出:
	1111
	3333
	成功
*/
async function fn1(){
      
	return  '成功';
}
async function fn2(){
    
	console.log(1111);
	// await 将异步代码转为同步结果,等着异步代码执行完才执行后面的代码
	let data = await fn1();  
	console.log(data);
	console.log(3333);
}
fn2();
/**
输出:
	1111
	成功
	3333
*/

同步异步的简单讲解就到这里了,若你有其它看法,欢迎指正,期待您的留言!

求学的三个条件是:多观察、多吃苦、多研究。——加菲劳

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_41967475/article/details/105821978

智能推荐

2021-10-11电子天平期间核查和日常核查管理方法_szhtw168的博客-程序员资料

电子天平是药品质量控制实验室最常见的称量器具,电子天平的合理使用和维护对检测数据的准确性起着重要的作用。根据我国《计量法》和《强制检定的工作计量器具检定管理办法》的规定,药品质量控制实验室的电子天平应定期定点由经授权的法定计量部门进行强制检定,按照JJG1036-2008《电子天平检定规程》[1]实施,检定周期一般不超过1年。除我国强制计量的规定外,目前国际通行的OQ、PQ及期间核查构成了量值溯源的重要保证。此外,药品质量控制实验室还须对电子天平进行日常核查。RB/T 214-2017《检验检测机构资质认

HDMI-CEC 在LG电视上的研究_usb-hdmi-cec_shallen320的博客-程序员资料

HDMI-CEC是HDMI的控制协议,使有HDMI的设备能通过HDMI线缆进行互相控制。CEC是Consumer Electronics Control(消费者电器控制)的缩写。本文探讨了HDMI-CEC在PC端的实现和应用

实验:Docker搭建WordPress5.9并连接MariaDB_小橘猫cate的博客-程序员资料

实验:Docker搭建WordPress5.9并连接MariaDB1、虚拟机CentOS7.5下载wordpress和mariadb镜像,查看本地镜像,2、通过run命令创建新的容器,[[email protected] ~]# docker run --name my_mariadb -p 3306:3306 --env MYSQL_ROOT_PASSWORD=root -d mariadb[[email protected] ~]# docker run --name my_wordpress.

unity使用gradle方式打包遇到的坑(1)_jiajiadejiali21的博客-程序员资料

在win上打包可能会遇到这样的错误Running dex as a separate process.To run dex in process, the Gradle daemon needs a larger heap.It currently has 1024 MB.For faster builds, increase the maximum heap size for th...

运维手册_weixin_34268310的博客-程序员资料

原文地址:http://blog.sina.com.cn/s/blog_87ace1a00101kp0y.html产品运维建议初步整理:1.要有专门的人负责运维,至少当非开发人员发现问题时,能够在第一时间找到问题处理人。2.每天定时查询服务器的运行状态,至少早上上班时和晚上下班前两次;每天下班前发送“日常运维报告”邮件给主要关系人;每周整理一次“周运维报告”,统一当周系统运行...

Luogu P2602 [ZJOI2010]数字计数_Top_xiao的博客-程序员资料

链接:https://www.luogu.org/problem/P2602/*首先我们要知道, 从 0 - 99, 0 - 999, 0 - 9999 , 每个数字出现的次数是一样的. 我们先算在 i 的位置, x 这个数出现了多少次, 9999 假设有四位数,我们现在推到第五位,那么第五位的数 x 出现的所有数就是, x + (0-9999), (0 - 9)+((0 -...

随便推点

MS-DOS 7.10完整安装版(含图文安装程序)_weixin_30764137的博客-程序员资料

大家知道,要想学习或使用DOS,安装一个DOS并进行实际操作是非常必要的。MS-DOS 7.10是一个非常好且强大实用的操作系统,而且兼容性和性能都十分强。要在系统中安装MS-DOS 7.10,可以使用MS-DOS 7.10安装程序自动将MS-DOS 7.10安装到系统中。MS-DOS 7.10安装程序是图形/菜单界面,并采用向导式进行。通过此安装程序,大家可以方便地将MS-DOS 7.10安装到...

pytorch - Tacotron2运行笔记_pytorch tcontron_赫凯的博客-程序员资料

搞了蛮多时间,就记录下 基于这个NVIDIA/tacotron2首先,Tacotron2 是一个端到端的,就是文字序列进去出来的是语音序列,分两个一个是从文字到梅尔频谱图,一个是从梅尔频谱图转化成语音,两部分再Navida pytorch 代码里是分开的,就一个一个训练,首先先看tacotron2 前端部分,就跟着步骤一步步来就可以了,其中要下载和自己显卡相匹配的PyTorch版本,训练应该没有...

【RTF】如何使用python读取RTF格式的文件_python 读取rtf_文西·达的博客-程序员资料

今天查了各种资料,最终还是吧这个问题解决了。尝试了pyRTF,可惜这个库是用来保存RTF的尝试了python-doc,这个库读取rtf文件失败尝试了open 编码格式gbk,中文汉字无法识别。。。。终于终于,找到了对应方法:win32com 因为我以前貌似安装过,所以不知道应该咋装,因为自带了。话不多说直接上代码# -*- coding:utf-8 -*-'...

Python基础-常见问题:运行代码时提示“SyntaxError: expected an indented block”,怎么解决呢?_syntaxerror: expected 'except' or 'finally' block_Python自动化办公社区的博客-程序员资料

运行代码时提示“SyntaxError: expected an indented block”,说明缩进有问题,请检查缩进后,调整正确即可。Python代码对缩进的要求非常严格,相同层次的代码必须具有同样的缩进量。...

ReentrantReadWriteLock详解_永远向前的麦田的博客-程序员资料

1、用法//初始化读锁和写锁ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); ReentrantReadWriteLock.ReadLock rlock = rwl.readLock();ReentrantReadWriteLock.WriteLock wlock = rwl.writeLock();//加解锁r...

推荐文章

热门文章

相关标签