99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

如何理解knockout執(zhí)行過(guò)程

發(fā)布時(shí)間:2016-07-28 20:14  回復(fù):0  查看:2606   最后回復(fù):2016-07-28 20:14  

knockout執(zhí)行過(guò)程是怎么樣的呢?你是不是還很迷惑。這里我就結(jié)合我自己學(xué)習(xí)knockout的總結(jié)和自己的開(kāi)發(fā)經(jīng)驗(yàn)給大家講解一些,有源碼喲。

 

一、執(zhí)行流程

如何理解knockout執(zhí)行過(guò)程

一、主要類分析

 

2.1. applyBindings中,創(chuàng)建bindingContext,然后執(zhí)行applyBindingsToNodeAndDescendantsInternal方法
2.2. applyBindinsToNodeAndDescendantsInteranl方法,主要完成當(dāng)前Node的綁定,以及子Node的綁定

 

function applyBindingsToNodeAndDescendantsInternal (bindingContext, nodeVerified, bindingContextMayDifferFromDomParentElement) {

        var shouldBindDescendants = true;

 

        // Perf optimisation: Apply bindings only if...

        // (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)

        //     Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those

        // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)

        var isElement = (nodeVerified.nodeType === 1);

        if (isElement) // Workaround IE <= 8 HTML parsing weirdness            ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);

 

        var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement)             // Case (1)

                               || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified);       // Case (2)

        if (shouldApplyBindings)

            shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, bindingContext, bindingContextMayDifferFromDomParentElement)['shouldBindDescendants'];

 

        if (shouldBindDescendants && !bindingDoesNotRecurseIntoElementTypes[ko.utils.tagNameLower(nodeVerified)]) {

            // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,

            //  * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,

            //    hence bindingContextsMayDifferFromDomParentElement is false

            //  * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may

            //    skip over any number of intermediate virtual elements, any of which might define a custom binding context,

            //    hence bindingContextsMayDifferFromDomParentElement is true

            applyBindingsToDescendantsInternal(bindingContext, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);

        }

    }

 

2.3. 進(jìn)入applyBindingsToNodeInternal方法,其中會(huì)調(diào)用bindingProvidergetBindingsAccessors方法(用于分析和獲取bindings數(shù)據(jù),主要分析data-bind屬性)
2.4. 創(chuàng)建dependentObservable對(duì)象(依賴監(jiān)控對(duì)象)

 

var bindings;

        if (sourceBindings && typeof sourceBindings !== 'function') {

            bindings = sourceBindings;

        } else {

            var provider = ko.bindingProvider['instance'],

                getBindings = provider['getBindingAccessors'] || getBindingsAndMakeAccessors; //自定義BingindHandler

 

            // Get the binding from the provider within a computed observable so that we can update the bindings whenever

            // the binding context is updated or if the binding provider accesses observables.

            var bindingsUpdater = ko.dependentObservable( //依賴監(jiān)控對(duì)象

                function() { //做了read、write處理,實(shí)現(xiàn)雙向關(guān)聯(lián)(只做了read),默認(rèn)會(huì)執(zhí)行一次read的。

                    bindings = sourceBindings ? sourceBindings(bindingContext, node) : getBindings.call(provider, node, bindingContext);

                    // Register a dependency on the binding context to support observable view models.

                    if (bindings && bindingContext._subscribable)

                        bindingContext._subscribable();

                    return bindings;

                },

                null, { disposeWhenNodeIsRemoved: node }

            );

 

            if (!bindings || !bindingsUpdater.isActive())

                bindingsUpdater = null;

        }

 

2.5. 然后分析bindings中每個(gè)binding,并將initupdate方法創(chuàng)建為一個(gè)dependentObservable對(duì)象(其中bindings的執(zhí)行是有順序的)。

 

二、BindingProvider分析

 

此類主要提供關(guān)于data-bind屬性的解析,主要提供getBindingsgetBindingsAccessors、parseBindingsString(內(nèi)容使用)方法輔助binding過(guò)程。創(chuàng)建function對(duì)象:

 

function createBindingsStringEvaluator(bindingsString, options) {

        // Build the source for a function that evaluates "expression"

        // For each scope variable, add an extra level of "with" nesting

        // Example result: with(sc1) { with(sc0) { return (expression) } }

        var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString, options),

            functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}"; //執(zhí)行with表達(dá)式

        return new Function("$context", "$element", functionBody);

    }

 

1、在分析bindings時(shí),會(huì)區(qū)分NodeType18的類型。如果是8(注釋)就會(huì)調(diào)用virtualElements類的virtualNodeBindingValue方法來(lái)分析binding結(jié)果。

 

四、bindings的排序技巧

 

查看自定義binding是否有after屬性,如果存在則進(jìn)行遞歸操作:

 

function topologicalSortBindings(bindings) {

        // Depth-first sort

        var result = [],                // The list of key/handler pairs that we will return

            bindingsConsidered = {},    // A temporary record of which bindings are already in 'result'

            cyclicDependencyStack = []; // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it

        ko.utils.objectForEach(bindings, function pushBinding(bindingKey) {

            if (!bindingsConsidered[bindingKey]) {

                var binding = ko['getBindingHandler'](bindingKey);

                if (binding) {

                    // First add dependencies (if any) of the current binding

                    if (binding['after']) { //依賴檢測(cè),將after的引用先添加到數(shù)組中,然后再添加當(dāng)前項(xiàng)                        cyclicDependencyStack.push(bindingKey);

                        ko.utils.arrayForEach(binding['after'], function(bindingDependencyKey) {

                            if (bindings[bindingDependencyKey]) {

                                if (ko.utils.arrayIndexOf(cyclicDependencyStack, bindingDependencyKey) !== -1) {

                                    throw Error("Cannot combine the following bindings, because they have a cyclic dependency: " + cyclicDependencyStack.join(", "));

                                } else {

                                    pushBinding(bindingDependencyKey);

                                }

                            }

                        });

                        cyclicDependencyStack.length--;

                    }

                    // Next add the current binding                    result.push({ key: bindingKey, handler: binding });

                }

                bindingsConsidered[bindingKey] = true;

            }

        });

 

五、注意

 

1.所有的dependentObservable對(duì)象,在創(chuàng)建的過(guò)程中都會(huì)默認(rèn)執(zhí)行一次readFunction方法。

 

 

 

 

原文來(lái)自:博客園/小龍女先生

您還未登錄,請(qǐng)先登錄

熱門帖子

最新帖子

?