Backbone源码解读(二)

1. 收场

强烈建议一边看着源码一边读本文章,本文不贴大段代码。源码地点
在写backbone运用的时刻,说实话,大部分的时候都是在写这三个模块的内容。关于这三个模块的剖析网上马马虎虎就能够找到一堆还不错的文章。但我愿望能够找到一条线索,能把各自模块的内部机理整顿清楚。就像前一篇文章中引见的Events那样。Events悉数模块实在就是经由过程一些外部的要领来修正内部对象的属性,从而到达事宜治理的目标。以一条线索来对待悉数模块,一切都清楚了然了。下面就最先了~

(近来要开学,要预备回学校上课,杂乱无章的东西许多,所以文章能够也会拖一阵子啦…然则我照样异常愿望能够写下来,半途而废的以为至心不好…

这一篇文章重要讲backboneModel, CollectionView。这三个模块有许多相似的处所。这篇文章不会把模块的每个要领都引见一遍,因为只要看源码就晓得,实在重要的要领只要几个,而许多其他的模块现实上只是在挪用这几个中心的要领罢了。

2. Model & Collection & View

首先讲一下三者的相似之处。这一节让我们来看看这三个模块一个团体组织。
这三个模块在组织上和Events差别。他们先经由过程以下体式格局来定义组织函数。(以View为例)

var View = Backbone.View = function(options) {
    // 组织函数的内容
};

组织函数的内部平常会做以下几个操纵:

  • 种种给内部对象设置属性。(种种this.a = b

  • 挪用preinitialize

this.preinitialize.apply(this, arguments);
  • 挪用initialize

this.initialize.apply(this, arguments);

各个模块的要领和属性是经由过程underscoreextend来取得的。注意在extend新到场的要领和属性中,以下划线开首的变量是内部函数名。(实在理论上用户也能够挪用这些要领,谁叫Javascript没有内部变量呢…)这些内部要领是供本身模块内部挪用的。

_.extend(View.prototype, Events, {
    // 这里是种种对View.prototype的拓展,定义种种要领
});

另有一个比较大的共同点,就是slient参数。这个参数决议了是不是要trigger一个事宜,在源码用占了很大的篇幅对其举行分类议论。

3. Model

3.1 症结要领

有一些症结的要领一进入函数就会根据传入的参数的形状举行变化。因为backbone一些要领支撑两个参数传入或许一个数组传入,这时刻须要有个推断。

3.2 set

set要领在model内里是个很不好明白的东西,看了网上大多数剖析以为都很隐约(而且碰到难明白的就用一些托言蒙混过去)。不得不说set内里庞杂精巧水平是每读一遍赞叹一遍。
我想以变量的角度来解说多是一个比较好的角度。

  • changingthis._changing
    假如这个函数只是从新实行到尾,那说实话,这两个变量没有任何意义。因为他们的值是肯定的。看函数开首:

var changing   = this._changing;
this._changing = true;

在函数末端:

this._changing = false;

这个changing将永久永久是false。我上网看到有人说多是webWorker,多线程相干的东西,但我直接在源码console的时刻却发明,这个changing是会变的,而且我用得是todo类型。todo类型没有任何相似webWorker的东西。这个假定猜想应当来讲是不准确的。(不过这篇文章讲得也很不错啊)
所以这个changing到底有什么用呢?答案就是递归函数set里明显没有递归啊?实在递归藏在了一切trigger的事宜的回调函数内里。源代码下面的这一段:

// You might be wondering why there's a `while` loop here. Changes can
// be recursively nested within `"change"` events.
while (this._pending) {
    options = this._pending;
    this._pending = false;
    this.trigger('change', this, options);
}

这一个while里的trigger使得函数发作递归,然后从新挪用set。如许的话,下一次changing就即是true了,这个变量的作用才发挥。能够看一下这个链接内里的解说。

  • current变量是用来作为援用转变attributes的,现实上是set能设置attributes的实质。

  • changes数组是用来寄存转变了的key的,用于后期的事宜触发。

  • changed & _previousAttributes
    把这两个放到一同是因为他们的一个迥殊的处所。我在todo的主函数的render内里console,发明不管我做什么操纵,changed === {},_previousAttributes没有发作转变。厥后在检察官方文档的时刻,才相识previous的用法:

var bill = new Backbone.Model({
  name: "Bill Smith"
});

bill.on("change:name", function(model, name) {
  alert("Changed name from " + bill.previous("name") + " to " + name);
});

bill.set({name : "Bill Jones"});

set要领在被挪用的时刻,previous只要在回调函数里才有效,也就是说,在回调函数表面想要用这个previous猎取前一个值是不能够的。它只能猎取到当前值。为何呢?源码做出相识释。当用户做出操纵须要用到set要领的时刻,实在set要领并非直接实行完就完毕了。在这个要领内里触发了许多的事宜,而previous只要在函数里触发了的事宜的回调函数“内里”才返回准确的“前一个值”。changed也同理,因为不管中心如何变化,递归,到末了它会被设置为{}

3.3 save

save要领的作用是把当前model的状况保存到数据库中,因而不可避免地要用到ajax。因为backbone已有了一个封装好的要领sync用于触发ajax,因而在save当中重点是设置参数。须要设置的有successerrormethod

  • success内里会挪用用户传入的回调函数并触发sync事宜示意已同步了。

  • error用封装好的wrapError函数,这个函数用得许多,用于处置惩罚毛病。

  • method根据现实要用那种要领设置
    个中比较值得注意的是wait参数。这个参数会影响页面更新的机遇。假如waittrue的话,就会须要比及服务器端相应才更新页面,不然就会马上更新。

3.4 destory

destory要领也是与ajax有密切联系的。重要也是设置ajax参数。它分了几种差别的状况并作出了相应的处置惩罚:

  • waitfalse,不必守候。提议delete请求,触发内部函数destory

  • waittrue,提议ajax,守候服务器相应才触发destory更新页面。

  • 这是一个新的model,那就不须要提议请求了。

3.5 isValid

考证函数,经由过程挪用内部函数_validate,在经由过程这个函数挪用validate函数。然后返回一个毛病,假如没有毛病就返回true,不然触发invalid,返回false

4. Collection

Collection相似一个数组,内里寄存着种种以model为组织的对象。在Collection中也有这情势的推断,假如传入的参数是单个对象就会被转换成数组。

4.1 set

这是Collection的一个很经常使用的要领,源码中这一段很长,也有点烦琐,然则没有迥殊难以明白的处所。悉数set的组织是:

  • 设置几个数组(下面会细致讲)

  • 设置现实的models(修正this.models

  • trigger事宜

重要来讲就是有以下几个症结点:

  • 假如不符合model情势,转换之。

  • 设置相应的插进去位置at

  • 设置set数组。set数组在内里作用是为给背面排序做预备。内里寄存的是新的Collectionmodels

  • 设置toAdd数组。这个数组是用于存储新建的正当的model,然后须要挪用内部函数_addReference设置索引于_byId数组,而且增添all事宜(背面就能够够经由过程model直接trigger事宜)。当slient不是true,后期能够经由过程遍历它来触发add事宜。

  • 设置toMerge数组。当这个model是底本已存在的model的时刻(cid婚配),就会修正,然后被push进这个数组中。

  • 设置toRemove数组。然后经由过程内部函数_removeModels删除那些已不在set内里的models

  • 修正this.models,分两种状况,一种是直接悉数替换掉,一种是背面再增添。

  • 假如silent不是true就要触发事宜。迥殊值得注意的一点是:这内里的事宜有两种,一种事宜是由Model发出的,一种事宜是有Collection发出的。从Model发出的事宜能够很轻易_addReference函数中发明

model.on('all', this._onModelEvent, this); 

在这里注册了,挪用的是_onModelEvent函数。而其他没有注册的函数应当是给使用者注册监听用的。

4.2 sort

sort所根据的是用户传入的comparator参数,这个参数能够是一个字符串也能够是一个函数,假如是字符串就经由过程underscoresortBy要领,假如是个函数就直接传入sort的第二个参数中。

4.3 fetch & create

fetchcreatebackbone与服务器端交互的一个接口。两个要领内部处置惩罚实在都很好明白,就是设置ajax参数。终究实质上都是触发sync。然则唯一差别的是fetch是经由过程本身的sync函数,但create是经由过程挪用modelsave,然后触发sync的。在

model.save(null, options);

随着这个save函数内里走,就会发明参数null传入是有意义的。在save内里的参数设置会很好地赋值并末了触发sync,而且有一个很风趣的点,就是这个createmodel传上服务器,然则这个model是一个相对自力的状况,仅仅经由过程它的Collection属性来维系和Collection的关联。那就请求后端须要把这一个model增添到相应的Collection数据内里去。

4.4 reference

Collection有一个值得关注的内部变量,那就是_byId,这个变量用cidid(所以model是一对一对涌现的)来存储Collection内里的model,轻易直接性的存取。在源码中有许多操纵目标就是删除,增添,猎取这个内部变量的值。

4.5 CollectionIterator

这东西我以为很有意义…在官方文档内里没有提到,然则因为涉及到ES6的东西所以以为有点眼前一亮的以为(哈哈哈),backbone在这里用了Symbol.iterator,详细用法在这个链接里有引见,照样挺清楚的。经由过程设置CollectionIteratorSymbol.iteratornext要领。它经由过程内部变量_kind来辨别品种,_index来肯定对应的next的效果,这个关于写迭代器照样有点自创意义的~

5. View

在写backbone运用的时刻,View写着写着会越来越大…追根溯源,就是View的代码很少…(大雾)。关于View,在写相干代码的时刻有一些值是须要设置的(可选的)。下面的代码就展示了可设置的参数,这些参数在View的要领中会用到(假如有的话)。

var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];

下面我会从两个大的方面来解读源码,一个是element,一个是Events。悉数View的源码事实上就是这两组东西。

5.1 Element

View字面意义是视图,而在浏览器中,视图就是html所显现的页面。每个View事实上就对应着html的一个元素(固然这个元素内里能够有许多许多元素)。这个元素默许标签是div。与元素相干的代码实在很简单,首先要认清this.elthis.$el。前者是真正的节点,后者则是jquery对象的节点。后者因为是jquery式的,因而就能够够做相干的jquery的操纵。因而事宜提议,删除节点,设置属性的操纵都是jqueryapithis.$el或其子节点的操纵。在进入组织函数的时刻会挪用一个叫_ensureElement的内部函数,在这个函数里会根据用户设置的参数去构建节点,末了展示到页面之上。

5.2 Events

事宜是View中异常重要的构成。这是用户能够操纵数据的一个接口。在View内里和数据相干的要领有delegateEventsdelegatesundelegateEventsundelegate。内里经由过程使用者设置的events属性来建立种种事宜,操纵种种事宜。

{
    'mousedown .title':  'edit',
    'click .button':     'save',
    'click .open':       function(e) { ... }
}

events相干代码很简单,然则有一个异常异常奇妙的处所:就是作者用了jquery事宜相干api定名空间。在delegate被挪用的时刻就给事宜加上了一个特定的定名空间。

delegate: function(eventName, selector, listener) {
    this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener);
    return this;
}

因而在后续须要对团体的一切事宜举行操纵的时刻就会轻易许多许多。

6. 末了的话

此次源码剖析不能百分百保证是准确的,有一些混淆了本身的思索。因为不想像其他大部分的源码剖析那样,关于题目隐约处置惩罚。但我以为照样有意义的,因为每个人读的角度不一样。兼听则明,也愿望读者能够包涵,愿望深刻明白backbone的读者也请多读几篇文章,多读几遍源码。下一篇文章要写router & history,这一个模块能够零丁拆出来作为SPA的一个进口,个人认为这部分时backbonebackbone(骨架)。

愿望能够对峙更下去吧,开学了,事变也最先多了起来…

本人照样backbone小白,假如那里说错了或许如何,请轻喷~互相进修~

下面是悉数的文章:

    原文作者:harryfyodor
    原文地址: https://segmentfault.com/a/1190000006731780
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞