Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4. backbone之Events实现 #4

Closed
funfish opened this issue Aug 12, 2017 · 0 comments
Closed

4. backbone之Events实现 #4

funfish opened this issue Aug 12, 2017 · 0 comments

Comments

@funfish
Copy link
Owner

funfish commented Aug 12, 2017

前言

记得某次在大神的博客里面讲技术选型,提到团队对Backbone的框架很熟悉,在一次开发的时候选用Backbone源码的一部分,再搭配其他的使用。虽然Backbone现在已经不流行了,但从几年前我就开始听说它的存在了,一直觉得这么神奇的框架肯定很有必要学习,看到大神提到选取Backbone源码的一部分,顿时觉得大神就是大神,对源码运用与此精通。最近有空看Backbone源码,细读时,如啃老牛肉,又硬又难吃,常常看了一部分忘记另外一部分,疼苦不堪,后来结合Backbone的api文档和里面的Todos例子顿时觉得,神清气爽,仿佛任督二脉都打通了,只是看过之后愈发觉得,Backbone框架已经不是前端的弄潮儿,只是接近2000+的源码,里面的MVC思想,值得去研究,而不是天天研究如何运用新框架的api

目的

刚开始读Backbone就被开头的Events弄得云里雾里的,应该很多人有这样的经历,于是想介绍Events的实现思路以及其中的疑难;

思路

var object = {};
_.extend(object, Backbone.Events);
object.on('expand', function(){ alert('expanded'); });
object.trigger('expand');

这是源码在介绍Events用到的例子,Events模块可以被扩展到任意的对象上面,而在其他的Bakbone模块如Model/Collection/View等,同样在其内部扩展了Events模块;
事件模块,无非就是实现注册动作,监听动作,对应的在Events里面主要是on,listenTo,off, stopListening和trigger这几个;
刚开始看的时候比较晕,后来一想从注册事件,到触发事件,看不懂究竟在做什么,那可不可以从后往前看,先看如何触发事件,在看如何注册事件,这么一想就事半功倍了。

从trigger函数开始,落着点在triggerEvents函数,而在传递的events,一层层回溯,正是this._events,于是triggerEvents主体表达式就是

this._events[name].callback.call(this._events[name].ctx)

这就完事了,也就是说on事件负责把事件对应的回调函数/上下文注册到this._events里面,然后需要trigger的时候,直接call就好,如此的简单明了。再看on事件的时候发现却实是如此;
on事件通过onApi将事件需要的回调和上下文写入this.__events[name]里面;形成事件名字和回调映射的关系;这一切都是如此的顺畅,直到回头看on事件,发现写入this._events[name]的混杂着listening: _this.listening。

奇形怪状的各种listening _listening listeningTo _listeners

在on下面还有:

if (_listening) {
  var listeners = this._listeners || (this._listeners = {});
  listeners[_listening.id] = _listening;
  _listening.interop = false;
}

更不要提listenTo函数,一开始看直接懵逼了,但是主要流程都懂了还怕这些listenXX干嘛?
于是整理了一下和listenXX有关的所有地方,发现有如下关系:

this._listeners[_listening.id] = _listening
_listening = this._listeningTo[id] = new Listening(this, obj)

理清关系后发现都是纸老虎,就是在this._listeners里面添加个id和new Listening(this, obj)键值嘛,每当有个新的对象要监听的时候,就在this._listener里面添加构造函数Listening(this, obj),而 _listeners则是个全局变量,用来传递这个构造函数。那细心的观众不难发现,this._listeningTo又是用来干嘛的?this._listeningTo不是和this._listener一摸一样的吗?
开始我也是很疑惑,明明就是两个一样的对象,到后台打印也是一摸一样的呀?那为何作者要写两个呢?直到有一天,看着this._listeningTo和this._listener发呆的时候,发现,咦?前者有个To,后面没有呀,listeningTo不就意味着某个对象监听另外一个对象,而listener更像是监听者监听某个动作,再看看源码,哦,this._listeningTo出现在listenTo事件里面,而this._listener出现在On事件里面,So两个是完全不一样的呀。。。只有在纯粹的listenTo里面才会一样,如果单独监听某个动作,那创建的构造函数Listening不会出现在this._listeningTo里面。。。。。。尽然如此简单。。。。。。

interop库互相操作理解

前面提到的on和listenTo,接下来可以看stopListening和off函数,本质上和之前提到的on和listenTo很相似,但是这里面反复提到listening.interop到底是什么东西呢?如果是真的话,则会执行listening.off/on函数,咦?前面不是已经执行了obj.off/on了吗?这又是有何作用,带着疑问翻看了backbone的issue,发现下面这条issue原来是当obj本身有on/off函数,而obj又不扩展Events,则会进入listening构造函数中保存的off/on事件。
另外值得一提的是在on事件里面,若listening.interop=true,在进行listening.on之前,已经将全局变量_listening设置为void 0,后面再进行on函数的时候,其option中保存的listening将不是Listening实例而是undefined,所以在off事件中进行listening.off事件,若this.interop=true则会再次进入off事件,而在offApi中,listening.off之前会判断之前存放在this._events[name]中对应的option是否保存Listening实例,而前文提到这个时候listening为undefined,故不会重复循环进入listening.off里面;

还剩下once相关的事件,看过underscore源码的你,或者是没有看过的你,肯定可以理解,这里就不解释了
由于水平有限,若有水平有限,有错误的地方还请提出来

@funfish funfish changed the title backbone之Events实现 4. backbone之Events实现 Mar 11, 2018
@funfish funfish closed this as completed Jun 2, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant