Emitter | 每天读一点Vue源码
2020/3/23 11:01:51
本文主要是介绍Emitter | 每天读一点Vue源码,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言
面试的时候经常被问一些Vue源码相关的问题,通常情况下, 我会在面试前恶补掘金上的面筋来对付面试,什么双向绑定的原理呀,什么虚拟dom树呀,实际上我压根儿就没仔细研究过,其一是自己真的比较菜,其二工作上也用不上,别自己给自己添堵。但后面想一下,很多事情,为之则易,不为则难,给自己设立困难(负重)才能进步,决定每天多一点Vue的源码,在Vue的源码选择上,我选择了最老的版本(0.1)😬(真的怕自己看起来吃力), 阅读的模式为通读,从易到难一个文件一个文件的看,看完一个文件后再看它的单元测试,等完全吃透后复制粘贴代码到本地运行测试用例为代码块写一些中文注释,打上tag推到自己的仓库,开始梳理写文章总结(之前有犹豫过是否应该在掘金上写文章,因为这类Vue源码解析的文章已经很多了,而且还写的很好,我再写一遍是否还存在意义,后面想还是写吧,流水总结也不错💧)。
正文
简单介绍
Emitter直译过来为发射器,Emitter的功能类似于dom对象事件,Emitter通过emit触发事件, dom通过dispatchEvent触发, Emitter通过on函数注册事件,dom对象通过addListener注册事件,dom和Emitter是不是可以看成你自己,自己和自己聊天,emit发,on收。
代码细节
要实现上面说到的功能实现思路大致为Emitter需要一个容器来存放通过on注册的处理函数,Emitter调用emit的时候,内部再调用on注册的处理函数,就两步是不是看起来很简单,下面的最简代码。
function Emitter () { this._cbs = {} // 容器 } var EmitterProto = Emitter.prototype EmitterProto.on = function (event, fn) { (this._cbs[event] = this._cbs[event] || []).push(fn) // 放入容器 } EmitterProto.emit = function (event) { var callbacks = this._cbs[event], args if (callbacks) { callbacks = callbacks.slice(0) args = slice.call(arguments, 1) for (var i = 0, len = callbacks.length; i < len; i++) { callbacks[i].apply(this._ctx, args) // 把注册的处理函数,遍历调用 } } } 复制代码
代码优化
调用优化
场景:现在要在Emitter上注册set,get,mutate三个事件,你应该会这样写:
var __emitter__ = new Emitter() __emitter__.on('set', function(){ // ... }) __emitter__.on('get', function(){ // ... }) __emitter__.on('mutate', function(){ // ... }) 复制代码
能不能像jquery那样链式调用了,如果是链式调用,代码应该如下:
var __emitter__ = new Emitter() __emitter__.on('set', function(){ // ... }).on('get', function(){ // ... }).on('mutate', function(){ // ... }) 复制代码
要怎么实现链式调用呢?其实很简单,返回this就可以了,
// ... EmitterProto.on = function (event, fn) { // ... return this } // ... 复制代码
这样的话,其他人使用你的Emitter就更加方便灵活了(服务他人🤘)。
性能优化
在emit函数里面,我们看见了这行代码callbacks[i].apply(this._ctx, args)
,掘金上有很多文章分析过apply/call的性能,结论是apply相对于call更耗能,Vue里面有成千上万的事件触发(Emitter会结合observer使用的),不是非常耗能吗?
其实在源码里面,上面的emit实现是applyEmit, 而emit函数接受固定的参数的,代码如下:
/** * The internal, faster emit with fixed amount of arguments * using Function.call */ // 我们可以在observer的源码里看到: a为key, b为value, c: propagate EmitterProto.emit = function (event, a, b, c) {} 复制代码
总结
通过对Emitter的阅读我们可以学到一个类似dom对象事件的内部实现,学习到链式调用,学习到call/apply之间的性能差异(大家可以搜掘金上相关的文章)。阅读源码的乐趣就在这里,总能通过源码学到以前没有注意到的知识,哈哈哈😄。
代码地址
持续更新...❤️
这篇关于Emitter | 每天读一点Vue源码的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-04package.json 文件位置在哪?-icode9专业技术文章分享
- 2024-10-01Craco.js学习:从入门到实践指南
- 2024-10-01Create-React-App学习:入门与实践指南
- 2024-10-01CSS-in-JS学习:从入门到实践指南
- 2024-09-30JSX语法学习:从入门到初步掌握
- 2024-09-30Mock.js学习:入门教程与实战演练
- 2024-09-30React Hooks学习:从入门到实践
- 2024-09-30受控组件学习:React中的基础入门教程
- 2024-09-29JS定时器教程:初学者必看指南
- 2024-09-29JS对象教程:初学者的全面指南