JS异步编程的一些总结
前情回顾
上篇文章主要分享了事件循环
的问题,包括Node
的事件循环和JS
的事件循环。它们有很多相似之处。今天要聊的是日常中的异步编程
实现方案。
JS中的异步编程
我们都知道JS是单线程的,一条任务执行完成之后才会执行下一条任务。这种模式存在两个问题,一是整体花费时间是所有任务的总和。而是一旦某段代码出现错误流程就会被阻塞
。如果界面的渲染依赖这段代码,反应到浏览器上就会影响界面的渲染流程,进而出现各种问题。
JS中最常见的解决这个问题的方法有这么几种:一是回调函数
。这里其实有一个问题,如何理解回调函数的异步执行??
。相信大家都写过这种代码:
function initPage(){
console.log("page-inited")
showMap()
}
function showMap(){
console.log('map-stand-by')
}
//
initPage()
这段代码毫无疑问是同步的,因为showMap()
要在initPage()
执行完成后才执行。回调函数则不同,回调函数其实是个高阶函数
,将函数作为参数传给另外一个函数,这样一来,整个过程不用阻塞,直接允许后续操作。
回调函数的主要问题是,假如后续操作有很多,则需要连续嵌套多层回调函数,即常说的回调地狱
。
第二种方式是发布-订阅模式
。发布订阅可以理解为一种消息通知机制。假如我们需要开发一套商城,必然有多个模块儿,登录
,导航
,个人中心
等等。假如导航模块儿依赖登录模块儿,我们的代码有可能是这样的:
loginModule.success(function(res){
navModule.setAvatar(res.avatar)
selfCenterModule.setInfo(res)
})
假如后期我们又新增加了N多模块,那么我们必然会在loginModule
的回调里添加更多的方法去设置对应模块儿的信息。
使用发布订阅以后,可以将这些模块儿解耦出来,不同的模块儿只需要订阅登录成功的消息事件即可。
// 导航
let navModule = (function(){
loginModule.listen('succ',function(res){
navModule.setAvatar(res.avatar)
})
// 个人中心
let selfCenterModule = (function(){
selfCenterModule.listen('succ',function(res){
selfCenterModule.setInfo(res.avatar)
})
})()
发布定阅的实现原理也非常简单:将订阅消息的回调函数放入一个数组缓存中,当触发这个消息时,从数组中取出对应的函数进行执行。
var Event = {
// 缓存列表
clientList:[],
listen:function(fn){
this.clientList.push(fn)
},
trigger:function(){
let self = this
// 遍历缓存列表
for(var i = 0;i<self.clientList.length;i++){
self.clientList[i]()
}
}
}
vuex
,redux
中都有使用。
第三种是Promise
。Promise在目前的开发中应该是使用最多的。它遵循PromiseA+
规范。对于Promise本人理解的不够深刻,需要单独思考然后在做总结。
第四种是async
和await
。这两个小东西被称作是异步编程的终极神器。async
和await
关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为
,而无需刻意地链式调用promise。因为,在promise语句中,我们只有在then()方法的回调中才可以取到返回值
。但是使用await
后,我们可以直接取到返回值
。这个问题理论上应该和生成器
有关。
需要注意的是await关键字只在async函数内有效。如果你在async函数体之外使用它,就会抛出语法错误 SyntaxError
。
最后一个我能想到的跟异步有关的方法是yield
。yield
关键字用来暂停和恢复一个生成器函数。好像这个方法之前也有很多人用。
yield关键字使生成器函数执行暂停,yield关键字后面的表达式的值返回给生成器的调用者。它可以被认为是一个基于生成器的版本的return关键字。对它有兴趣的可以去看下迭代器
和生成器
的知识点。
题外话
今天在思考一个问题,雍正王朝里,众皇子在争夺皇位的时候。邬思道对雍正说:“争是不争,不争是争。”表面上是劝他不要争,本质上还是告诉他要去争。只是做事都讲求方法罢了。
最后说两句
-
动一动您发财的小手, 「点个赞吧」
-
动一动您发财的小手, 「点个在看」
-
都看到这里了,不妨 「加个关注」
-
不妨 「转发一下」
,好东西要记得分享