成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

Backbone使用總結(jié)

gotham / 1086人閱讀

摘要:原文使用總結(jié)事件模型及其原理就是事件實(shí)現(xiàn)的核心,它可以讓對(duì)象擁有事件能力對(duì)象通過偵聽其他對(duì)象,通過觸發(fā)事件。可以脫離的,在自定義的對(duì)象上使用事件執(zhí)行結(jié)果的和等核心類,都是繼承自的。在內(nèi)部使用事件基類的完成這個(gè)動(dòng)作。

開始在項(xiàng)目中大規(guī)模使用backbone,一路磕磕碰碰,邊做邊學(xué)習(xí)邊體會(huì),有一些心得和體會(huì),記錄在本文中。原文:Backbone使用總結(jié)

事件模型及其原理

Backbone.Events就是事件實(shí)現(xiàn)的核心,它可以讓對(duì)象擁有事件能力

var Events = Backbone.Events = { .. }

對(duì)象通過listenTo偵聽其他對(duì)象,通過trigger觸發(fā)事件??梢悦撾xBackbone的MVC,在自定義的對(duì)象上使用事件

var model = _.extend({},Backbone.Events);
var view = _.extend({},Backbone.Events);
view.listenTo(model,"custom_event",function(){ alert("catch the event") });
model.trigger("custom_event");

執(zhí)行結(jié)果:

Backbone的Model和View等核心類,都是繼承自Backbone.Events的。例如Backbone.Model:

var Events = Backbone.Events = { .. }

var Model = Backbone.Model = function(attributes, options) {
    ...
};

_.extend(Model.prototype, Events, { ... })

從原理上講,事件是這么工作的:

被偵聽的對(duì)象維護(hù)一個(gè)事件數(shù)組_event,其他對(duì)象在調(diào)用listenTo時(shí),會(huì)將事件名與回調(diào)維護(hù)到隊(duì)列中:

一個(gè)事件名可以對(duì)應(yīng)多個(gè)回調(diào),對(duì)于被偵聽者而言,只知道回調(diào)的存在,并不知道具體是哪個(gè)對(duì)象在偵聽它。當(dāng)被偵聽者調(diào)用trigger(name)時(shí),會(huì)遍歷_event,選擇同名的事件,并將其下面所有的回調(diào)都執(zhí)行一遍。

需要額外注意的是,Backbone的listenTo實(shí)現(xiàn),除了使被偵聽者維護(hù)對(duì)偵聽者的引用外,還使偵聽者也維護(hù)了被偵聽者。這是為了在恰當(dāng)?shù)臅r(shí)候,偵聽者可以單方面中斷偵聽。因此,雖然是循環(huán)引用,但是使用Backbone的合適的方法可以很好的維護(hù),不會(huì)有問題,在后面的內(nèi)存泄露部分將看到。

另外,有時(shí)只希望事件在綁定后,當(dāng)回調(diào)發(fā)生后,就接觸綁定。這在一些對(duì)公共模塊的引用時(shí)很有用。listenToOnce可以做到這一點(diǎn)

與服務(wù)器同步數(shù)據(jù)

backbone默認(rèn)實(shí)現(xiàn)了一套與RESTful風(fēng)格的服務(wù)端同步模型的機(jī)制,這套機(jī)制不僅可以減輕開發(fā)人員的工作量,而且可以使模型變得更為健壯(在各種異常下仍能保持?jǐn)?shù)據(jù)一致性)。不過,要真正發(fā)揮這個(gè)功效,一個(gè)與之匹配的服務(wù)端實(shí)現(xiàn)是很重要的。為了說明問題,假設(shè)服務(wù)端有如下REST風(fēng)格的接口:

GET /resources 獲取資源列表

POST /resources 創(chuàng)建一個(gè)資源,返回資源的全部或部分字段

GET /resources/{id} 獲取某個(gè)id的資源詳情,返回資源的全部或部分字段

DELETE /resources/{id} 刪除某個(gè)資源

PUT /resources/{id} 更新某個(gè)資源的全部字段,返回資源的全部或部分字段

PATCH /resources/{id} 更新某個(gè)資源的部分字段,返回資源的全部或部分字段

backbone會(huì)使用到上面這些HTTP方法的地方主要有以下幾個(gè):

Model.save() 邏輯上,根據(jù)當(dāng)前這個(gè)model的是否具有id來判斷應(yīng)該使用POST還是PUT,如果model沒有id,表示是新的模型,將使用POST,將模型的字段全部提交到/resources;如果model具有id,表示是已經(jīng)存在的模型,將使用PUT,將模型的全部字段提交到/resources/{id}。當(dāng)傳入options包含patch:true的時(shí)候,save會(huì)產(chǎn)生PATCH。

Model.destroy() 會(huì)產(chǎn)生DELETE,目標(biāo)url為/resources/{id},如果當(dāng)前model不包含id時(shí),不會(huì)與服務(wù)端同步,因?yàn)榇藭r(shí)backbone認(rèn)為model在服務(wù)端尚不存在,不需要?jiǎng)h除

Model.fetch() 會(huì)產(chǎn)生GET,目標(biāo)url為/resources/{id},并將獲得的屬性更新model。

Collection.fetch() 會(huì)產(chǎn)生GET,目標(biāo)url為/resources,并對(duì)返回的數(shù)組中的每個(gè)對(duì)象,自動(dòng)實(shí)例化model

Collection.create() 實(shí)際將調(diào)用Model.save

options參數(shù)存在于上面任何一個(gè)方法的參數(shù)列表中,通過options可以修改backbone和ajax請(qǐng)求的一些行為,可以使用的options包括:

wait: 可以指定是否等待服務(wù)端的返回結(jié)果再更新model。默認(rèn)情況下不等待

url: 可以覆蓋掉backbone默認(rèn)使用的url格式

attrs: 可以指定保存到服務(wù)端的字段有哪些,配合options.patch可以產(chǎn)生PATCH對(duì)模型進(jìn)行部分更新

patch: 指定使用部分更新的REST接口

data: 會(huì)被直接傳遞給jquery的ajax中的data,能夠覆蓋backbone所有的對(duì)上傳的數(shù)據(jù)控制的行為

其他: options中的任何參數(shù)都將直接傳遞給jquery的ajax,作為其options

backbone通過Model的urlRoot屬性或者是Collectionurl屬性得知具體的服務(wù)端接口地址,以便發(fā)起ajax。在Model的url默認(rèn)實(shí)現(xiàn)中,Model除了會(huì)考察urlRoot,第二選擇會(huì)是Model所在Collection的url,所有有時(shí)只需要在Collection里面書寫url就可以了。

Backbone會(huì)根據(jù)與服務(wù)端要進(jìn)行什么類型的操作,決定是否要添加idurl后面,以下代碼是Model的默認(rèn)url實(shí)現(xiàn):

url: function () {
    var base =
      _.result(this, "urlRoot") ||
      _.result(this.collection, "url") ||
      urlError();
    if (this.isNew()) return base;
    return base.replace(/([^/])$/, "$1/") + encodeURIComponent(this.id);
},

其中的正則式/([^/])$/是個(gè)很巧妙的處理,它解決了url最后是否包含"/"的不確定性。

  

這個(gè)正則匹配的是行末的非/字符,這樣,像/resources這樣的目標(biāo)會(huì)匹配s,然后replace中使用分組編號(hào)$1捕獲了s,將s替換為s/,這樣就自動(dòng)加上了缺失的/;而當(dāng)/resources/這樣目標(biāo)卻無法匹配到結(jié)果,也就不需要替換了。

Model和Collection的關(guān)系

在backbone中,即便一類的模型實(shí)例的確是在一個(gè)集合里面,也并沒有強(qiáng)制要求使用集合類。但是使用集合有一些額外的好處,這些好處包括:

url繼承

Model屬于Collection后,可以繼承Collection的url屬性。上面一節(jié)已經(jīng)提到了

underscore集合能力

Collection沿用了underscore90%的集合和數(shù)組操作,使得集合操作極其方便:

// Underscore methods that we want to implement on the Collection.
// 90% of the core usefulness of Backbone Collections is actually implemented
// right here:
var methods = ["forEach", "each", "map", "collect", "reduce", "foldl",
"inject", "reduceRight", "foldr", "find", "detect", "filter", "select",
"reject", "every", "all", "some", "any", "include", "contains", "invoke",
"max", "min", "toArray", "size", "first", "head", "take", "initial", "rest",
"tail", "drop", "last", "without", "difference", "indexOf", "shuffle",
"lastIndexOf", "isEmpty", "chain", "sample"];

Backbone巧妙的使用下面的代碼將這些方法附加到Collection中:

// Mix in each Underscore method as a proxy to `Collection#models`.
_.each(methods, function (method) {
    Collection.prototype[method] = function () {
        var args = slice.call(arguments);   //將參數(shù)數(shù)組轉(zhuǎn)化成真正的數(shù)組
        args.unshift(this.models);          //將Collection真正用來維護(hù)集合的數(shù)組,作為第一個(gè)個(gè)參數(shù)
        return _[method].apply(_, args);    //使用apply調(diào)用underscore的方法
    };
});
自動(dòng)偵聽和轉(zhuǎn)發(fā)集合中的Model事件

集合能夠自動(dòng)偵聽并轉(zhuǎn)發(fā)集合中的元素的事件,還有一些事件集合會(huì)做相應(yīng)的特殊處理,這些事件包括:

destroy 偵聽到元素的destroy事件后,會(huì)自動(dòng)將元素從集合中移除,并引發(fā)remove事件

change:id 偵聽到元素的id屬性被change后,自動(dòng)更新內(nèi)部對(duì)model的引用關(guān)系

自動(dòng)模型構(gòu)造

利用Collectionfetch,可以加載服務(wù)端數(shù)據(jù)集合,與此同時(shí),可以自動(dòng)創(chuàng)建相關(guān)的Model實(shí)例,并調(diào)用構(gòu)造方法

元素重復(fù)判斷

Collection會(huì)根據(jù)ModelidAttribute指定的唯一鍵,來判斷元素是否重復(fù),默認(rèn)情況下唯一鍵是id,可以重寫idAttribute來覆蓋。當(dāng)元素重復(fù)的時(shí)候,可以選擇是丟棄重復(fù)元素,還是合并兩種元素,默認(rèn)是丟棄的

模型轉(zhuǎn)化

有時(shí)從REST接口得到的數(shù)據(jù)并不能完全滿足界面的處理需求,可以通過Model.parse或者Collection.parse方法,在實(shí)例化Backbone對(duì)象前,對(duì)數(shù)據(jù)進(jìn)行預(yù)處理。大體上,Model.parse用來對(duì)返回的單個(gè)對(duì)象進(jìn)行屬性的處理,而Collection.parse用來對(duì)返回的集合進(jìn)行處理,通常是過濾掉不必要的數(shù)據(jù)。例如:

//只挑選type=1的book
var Books = Backbone.Collection.extend({
    parse:function(models,options){
        return _.filter(models , function(model){
            return model.type == 1;
        })
    }
})


//為Book對(duì)象添加url屬性,以便渲染
var Book = Backbone.Model.extend({
    parse: function(model,options){
        return _.extend(model,{ url : "/books/" + model.id });
    }
})

通過Collection的fetch,自動(dòng)實(shí)例化的Model,其parse也會(huì)被調(diào)用。

模型的默認(rèn)值

Model可以通過設(shè)置defaults屬性來設(shè)置默認(rèn)值,這很有用。因?yàn)?,無論是模型還是集合,fetch數(shù)據(jù)都是異步的,而往往視圖的渲染確實(shí)很可能在數(shù)據(jù)到來前就進(jìn)行了,如果沒有默認(rèn)值的話,一些使用了模板引擎的視圖,在渲染的時(shí)候可能會(huì)出錯(cuò)。例如underscore自帶的視圖引擎,由于使用with(){}語法,會(huì)因?yàn)閷?duì)象缺乏屬性而報(bào)錯(cuò)。

視圖的el

Backbone的視圖對(duì)象十分簡(jiǎn)答,對(duì)于開發(fā)者而言,僅僅關(guān)心一個(gè)el屬性即可。el屬性可以通過五種途徑給出,優(yōu)先級(jí)從高到低:

實(shí)例化View的時(shí)候,傳遞el

在類中聲明el

實(shí)例化View的時(shí)候傳入tagName

在類中聲明tagName

以上都沒有的情況下使用默認(rèn)的"div"

究竟如何選擇,取決于以下幾點(diǎn):

一般而言,如果模塊是公用模塊,在類中不提供el,而是讓外部在實(shí)例化的時(shí)候傳入,這樣可以保持公共的View的獨(dú)立性,不至于依賴已經(jīng)存在的DOM元素

tagName一般對(duì)于自成體系的View有用,比如table中的某行tr,ul中的某個(gè)li

有些DOM事件必須在html存在的情況下才能綁定成功,比如blur,對(duì)于這種View,只能選擇已經(jīng)存在的html

視圖類還有幾個(gè)屬性可以導(dǎo)出,由外部初始化,它們是:

// List of view options to be merged as properties.
var viewOptions = ["model", "collection", "el", "id", "attributes", "className", "tagName", "events"];
內(nèi)存泄漏

事件機(jī)制可以很好的帶來代碼維護(hù)的便利,但是由于事件綁定會(huì)使對(duì)象之間的引用變得復(fù)雜和錯(cuò)亂,容易造成內(nèi)存泄漏。下面的寫法就會(huì)造成內(nèi)存泄漏:

var Task = Backbone.Model.extend({})

var TaskView = Backbone.View.extend({
    tagName: "tr",
    template: _.template("<%= id %><%= summary %><%= description %>"),
    initialize: function(){
        this.listenTo(this.model,"change",this.render);
    },
    render: function(){
        this.$el.html( this.template( this.model.toJSON() ) );
        return this;
    }
})

var TaskCollection = Backbone.Collection.extend({
    url: "http://api.test.clippererm.com/api/testtasks",
    model: Task,
    comparator: "summary"
})

var TaskCollectionView = Backbone.View.extend({
    initialize: function(){
        this.listenTo(this.collection, "add",this.addOne);
        this.listenTo(this.collection, "reset",this.render);
    },
    addOne: function(task){
        var view = new TaskView({ model : task });
        this.$el.append(view.render().$el);
    },
    render: function(){
        var _this = this;

        //簡(jiǎn)單粗暴的將DOM清空
        //在sort事件觸發(fā)的render調(diào)用時(shí),之前實(shí)例化的TaskView對(duì)象會(huì)泄漏
        this.$el.empty();

        this.collection.each(function(model){
            _this.addOne(model);
        })

        return this;
    }

})

使用下面的測(cè)試代碼,并結(jié)合Chrome的堆內(nèi)存快照來證明:

var tasks = null;
var tasklist = null;

$(function () {
    // body...
    $("#start").click(function(){
        tasks = new TaskCollection();
        tasklist = new TaskCollectionView({
            collection : tasks,
            el: "#tasklist"
        })

        tasklist.render();
        tasks.fetch();
    })

    $("#refresh").click(function(){
        tasks.fetch({ reset : true });
    })

    $("#sort").click(function(){
        //將偵聽sort放在這里,避免第一次加載數(shù)據(jù)后的自動(dòng)排序,觸發(fā)的sort事件,以至于混淆
        tasklist.listenToOnce(tasks,"sort",tasklist.render);
        tasks.sort();
    })
})

點(diǎn)擊開始,使用Chrome的"Profile"下的"Take Heap Snapshot"功能,查看當(dāng)前堆內(nèi)存情況,使用child類型過濾,可以看到Backbone對(duì)象實(shí)例一共有10個(gè)(1+1+4+4):

  

之所以用child過濾,因?yàn)槲覀兊念惱^承自Backbone的類型,而繼承使用了重寫原型的方法,Backbone在繼承時(shí),使用的變量名為child,最后,child被返回出來了

點(diǎn)擊排序后,再次抓取快照,可以看到實(shí)例個(gè)數(shù)變成了14個(gè),這是因?yàn)?,?b>render過程中,又創(chuàng)建了4個(gè)新的TaskView,而之前的4個(gè)TaskView并沒有釋放(之所以是4個(gè)是因?yàn)橛涗浀臈l數(shù)是4)

再次點(diǎn)擊排序,再次抓取快照,實(shí)例數(shù)又增加了4個(gè),變成了18個(gè)!

那么,為什么每次排序后,之前的TaskView無法釋放呢。因?yàn)門askView的實(shí)例都會(huì)偵聽model,導(dǎo)致model對(duì)新創(chuàng)建的TaskView的實(shí)例存在引用,所以舊的TaskView無法刪除,又創(chuàng)建了新的,導(dǎo)致內(nèi)存不斷上漲。而且由于引用存在于change事件的回調(diào)隊(duì)列里,model每次觸發(fā)change都會(huì)通知舊的TaskView實(shí)例,導(dǎo)致執(zhí)行很多無用的代碼。那么如何改進(jìn)呢?

修改TaskCollectionView:

var TaskCollectionView = Backbone.View.extend({
    initialize: function(){
        this.listenTo(this.collection, "add",this.addOne);
        this.listenTo(this.collection, "reset",this.render);
        //初始化一個(gè)view數(shù)組以跟蹤創(chuàng)建的view
        this.views =[]
    },
    addOne: function(task){
        var view = new TaskView({ model : task });
        this.$el.append(view.render().$el);
        //將新創(chuàng)建的view保存起來
        this.views.push(view);
    },
    render: function(){
        var _this = this;

        //遍歷views數(shù)組,并對(duì)每個(gè)view調(diào)用Backbone的remove
        _.each(this.views,function(view){
            view.remove().off();
        })

        //清空views數(shù)組,此時(shí)舊的view就變成沒有任何被引用的不可達(dá)對(duì)象了
        //垃圾回收器會(huì)回收它們
        this.views =[];
        this.$el.empty();

        this.collection.each(function(model){
            _this.addOne(model);
        })

        return this;
    }

})

Backbone的View有一個(gè)remove方法,這個(gè)方法除了刪除View所關(guān)聯(lián)的DOM對(duì)象,還會(huì)阻斷事件偵聽,它通過在listenTo方法時(shí)記錄下來的那些被偵聽對(duì)象(上文事件原理中提到),來使這些被偵聽的對(duì)象刪除對(duì)自己的引用。在remove內(nèi)部使用事件基類的stopListening完成這個(gè)動(dòng)作。
上面的代碼使用一個(gè)views數(shù)組來跟蹤新創(chuàng)建的TaskView對(duì)象,并在render的時(shí)候,依次調(diào)用這些視圖對(duì)象的remove,然后清空數(shù)組,這樣這些TaskView對(duì)象就能得到釋放。并且,除了調(diào)用remove,還調(diào)用了off,把視圖對(duì)象可能的被外部的偵聽也斷開。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/107005.html

相關(guān)文章

  • 基于 Backbone + node 的個(gè)人簡(jiǎn)歷生成器(個(gè)人學(xué)習(xí)總結(jié)

    摘要:應(yīng)用的功能這個(gè)應(yīng)用是一個(gè)個(gè)人簡(jiǎn)歷生成器。比較好的教程有這一個(gè)。這樣的命名污染問題自然顯而易見。而且發(fā)出多次請(qǐng)求也會(huì)影響性能。明顯不利于維護(hù)。然而我希望能夠不發(fā)生變化,因?yàn)槭窃谖募那疤嵯碌臉?biāo)簽頁,不能換一個(gè)標(biāo)簽就重建一個(gè)。 為什么學(xué)習(xí)backbone?這是個(gè)好問題。在這個(gè)前端框架爆炸的年代,比起backbone,對(duì)開發(fā)來說有更多更好的選擇,react,vue,angular等等。但這些...

    lansheng228 評(píng)論0 收藏0
  • Backbone精髓,觀察者模式和事件

    摘要:原文精髓,觀察者模式和事件交互邏輯更需要設(shè)計(jì)模式設(shè)計(jì)模式將人們?cè)谝酝拈_發(fā)過程中的經(jīng)驗(yàn)加以總結(jié),以指導(dǎo)后人。的事件根據(jù)上面討論,要實(shí)現(xiàn)觀察者模式,事件是非常重要的機(jī)制??偨Y(jié)雖然是模式的框架,但是其核心卻是界面的觀察者模式和事件機(jī)制。 前言 本人并非專業(yè)的前端,只是由于需要被迫轉(zhuǎn)做一段時(shí)間的前端,一段時(shí)間以來開始探索javascript上的MVC模式,最終打算從Backbone下手。在...

    Snailclimb 評(píng)論0 收藏0
  • Backbone 源碼解讀(一)

    1. 開場(chǎng) 1.1 MVC? MVC是一種GUI軟件的一種架構(gòu)模式。它的目的是將軟件的數(shù)據(jù)層(Model)和視圖(view)分開。Model連接數(shù)據(jù)庫,實(shí)現(xiàn)數(shù)據(jù)的交互。用戶不能直接和數(shù)據(jù)打交道,而是需要通過操作視圖,然后通過controller對(duì)事件作出響應(yīng),最后才得以改變數(shù)據(jù)。最后數(shù)據(jù)改變,通過觀察者模式更新view。(所以在這里需要用到設(shè)計(jì)模式中的觀察者模式) 1.2 Smalltalk-80...

    Kosmos 評(píng)論0 收藏0
  • 使用 Backbone.Marionette 管理復(fù)雜 UI 交互

    摘要:所以大量的問題都留給開發(fā)者自己想辦法來解決,因此遭到吐槽當(dāng)然,使用純開發(fā)一個(gè)復(fù)雜應(yīng)用時(shí),情況就會(huì)變得非常糟糕。管理復(fù)雜的交互自己維護(hù)。影響了集合的排列。在中調(diào)用這樣做是不對(duì)的,因?yàn)闀?huì)讓應(yīng)用越來越復(fù)雜的。 只扯蛋,不給代碼,就是耍流氓 -- honger。 完整的 tutorial 代碼 戳這里, 因?yàn)槲沂褂玫氖?commonjs 規(guī)范,基于 spm 的,你可以先安裝,然后運(yùn)行它。更多 ...

    Loong_T 評(píng)論0 收藏0
  • [譯] 在 Nashron 中使用 Backbone.js

    摘要:原文譯者飛龍協(xié)議這個(gè)例子展示了如何在的引擎中使用模型。在年三月首次作為的一部分發(fā)布,并通過以原生方式在上運(yùn)行腳本擴(kuò)展了的功能。將二者放在一起下一個(gè)目標(biāo)是在中,例如在服務(wù)器上復(fù)用模型。最后,我們?cè)谥姓{(diào)用函數(shù)??偨Y(jié)在中復(fù)用現(xiàn)存的庫十分簡(jiǎn)單。 原文:Using Backbone.js with Nashorn 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 這個(gè)例子展示了如何在Java8...

    tabalt 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<