JS异步编程
一.前导内容
在谈及具体的异步编程前,我们还需要知道何为同步编程,何为异步编程,这两者工作可是有着天差地别。
1.1 何为同步?何为异步?
那让我来举个栗子吧:假如你需要去做两件事,分别是去煮饭,听一首歌,那么,煮完饭再去听歌的执行流程是同步编程流程。而先煮饭,在煮饭的过程中去听歌的执行流程则是异步编程流程。
1.2 Javascript为什么是单线程
JS原本的任务就是负责浏览器和用户之间的交互功能,因为JS要操作DOM,所以必须是单线程的,如果你是JS的话,请你想想如果有多个线程同时操作同一个DOM,想必你会抓狂的吧。正因为如此,所以排队等待时间未免太过漫长,所以才有了我们现在口中的JS异步编程的方案。
二.异步编程的核心与方法
2.1 如何实现异步编程?异步编程的核心是什么?
实现异步编程的方案有很多,例如:回调函数、promise对象,事件监听、发布/订阅等等方案,但万变不离其中,所有异步编程的核心就是回调函数。下面我来举例具体说明一下什么是回调函数:
假如在煮好饭后要把听歌的耳机放到耳机架上,那么就要把这个事告诉你对象,那异步流程就变成了——你先煮饭,然后告诉你对象等你听完歌需要把耳机放到耳机架上,然后你再去听歌。在这个流程中,把耳机放回耳机架是回调函数,也就是在任务完成后你需要执行的操作,你就是异步操作的调用者,你对象就是异步操作的执行者,总结起来就是——由调用者定义,交给执行者执行的函数,就是回调函数。
2.2 回调地狱问题如何解决?
说起回调地狱,想必很多小伙伴并不陌生,这个问题也困扰着当时初学JS的我,想当初可是被这个问题折磨了一段时间。接下来就由我给大家说说回调地狱,具体来说回调地狱就是,当你执行DOM事件时,比如在页面上点击链接、回车等操作,浏览器都会悄悄地向服务端发送很多个http请求,携带后台可识别的参数,等待服务器返回数据,这个过程是异步回调的,当很多功能环环依赖时,代码会一层一层的嵌套起来,看起来十分庞大且恶心.
正是因为回调地狱不利于阅读,同时也不利于维护,所以前辈们为了解决这一问题,在很多方面做出了努力,这个时候我要跟大家分享一个JS异步编程的一个核心要点——promise,下面请用心分析我所说的内容:
(一)何为promise?
promise是一个构造函数,返回一个promise对象。一个promise指的是一个可能会在未来的某个时间点产生一个单一值的对象。我这里有一个很好的说法可以描述一下promise的机制:
好比你去汉堡店买汉堡包吃,你已经付好了钱,但是却被告知汉堡包已经售空,而店员为了解决你的问题,给了你一张汉堡兑换券,这张券不会过期,她让你明天再来拿券兑换汉堡包。虽然你的券可以换到汉堡包,但是你也不能确定你明天来时是否有汉堡可以兑换,但可以确定的是,你一定能在未来的某一天,兑换到这个汉堡包。
(二)promise自身的三种状态 (状态改变后就不会再变化)
(1)fulfilled:成功
(2)rejected:失败
(3)pending:等待
(三)promise的用法
promise给定了一些原型方法来进行状态处理
1.promise.prototype.then :
promise对象通过内部resolve函数完成状态的pending ->fulfilled。之后promise将保留这个状态。可以通过then去处理状态。例:pm.then( (val) =>{console.log(val); } )
处理rejected状态,then方法可接收两个函数
new Promise(function(resolve,reject){
setTimeout(() =>{
reject(new Error('err'))
},2000).then(null,(error) =>{
console.log(error);
})
})
2.promise.prototype.catch:
用来做错误统一处理,这样的链式调用中我们只需要用then来处理fulfilled状态,在链的末尾加上catch来统一处理错误。
new Promise((resolve,reject) =>{
setTimeout(() =>{
resolve = 100;
},2000).then(result =>{
return result * num;
return result / 2;}).catch(err =>{
console.log(err);
})
})
3.promise.prototype.finally():
这个API放在结尾,这时候你们肯定会好奇这是为什么呢?因为它不管前面的promise变为什么,它都会执行里面的回调函数。
new Promise((resolve,reject) =>{
setTimeout(() =>{
resolve = 100;
},2000).then(result =>{
return result * num;
return result / 2;}).catch(err =>{
console.log(err);
console.log('complete')
})
})
4.promise.all
Promise.all([A,B]).then(resA,resB) =>{
//do something
}
5.promise链式调用
promise对象的then方法会返回一个权限的promise对象
后面的then方法就是为了上一个then返回的promise注册回调
前面的then方法中回调函数的返回值会作为后面then方法回调的参数
如果回调返回的是Promise,后面的then方法的回调会等待它的结束
2.3 EventlLoop的执行顺序
EventLoop被称作事件轮询,也称为事件循环,而EventLoop的作用只有一个:监听调用栈和消息队列,一旦调用栈清空,EventLoop就会从消息队列中取出第一个回调函数,压入栈中执行它。
而就我个人的观点来看,我是这么理解它的:代码从上到下执行,如果遇到微任务就放到微任务队列中,遇到宏任务就放到宏任务队列中,所有代码被执行栈执行完后,先去微任务列表中执行任务,待解决所有微任务后,再去宏任务队列解决所有宏任务。
注意:
1.每当执行完当前宏任务时,都会返回微任务列表看是否有微任务需要执行,若存在微任务则先执行微任务,若没有微任务存在,则执行剩下的宏任务。
2.微任务不需要到队列队尾进行排队处理。
今天的分享就到这啦,这里是一条从艺术行业初入前端的小咸鱼,欢迎大家提出宝贵的建议,并一起讨论前端的技术知识,希望大家都能在不久的将来成为一名前端老鸟。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!