After two weeks of performance optimization, Avalon finally achieve the goal of a page binding to tens of thousands of times when not Cotton's target (angular limit is 2000). Now take a break and summarize some of the Avalon problems.
The first is how to monitor the problem. All MVVM there are probably three ways to associate properties in a VM with bound attributes in a view: angular is to precompile the function body, to replace the inside assignment statement, the value statement with the Set,get method, and then to do the dirty detection trigger by a specific method. or manually triggered; Ko is a layer of the VM's properties with a monitoring function, a full event-driven trigger, and Avalon is a object.defineproperties rewrite of the internal set,get function, a full event-driven trigger. In addition to EMBERJS, it is the unified use of God Set,get method to contact all values assigned to the portal, the event-driven trigger, is a angular improvement. From the user experience, Avalon implementation is the best, because it is not to change user habits, emberjs second, forced to use the Set,get method, Ko let function, array into a function, so that users feel very Shong, angular the worst, a lot of nausea limitations, can not directly operate the VM. This situation occurs because Object.defineproperty is not compatible, although it is IE8 support, but it only exists on the element node. Unless you abandon the IE8. It's not a problem if I find VBScript directly. My advantage is that I knew from the beginning that there was a VBS that existed, and began to use it at the beginning of the Avalon implementation.
The implementation of the
Ms-if, in the final analysis, is a lifecycle design issue, how to destroy a binding and allow it to survive in exceptional circumstances. The point of association between a VM and a view is the binding attribute, the Binding property is converted to an evaluation function, and the evaluation function will form an object in an array with its contextual environment (such as its element node, its original binding property name, value, type, filter definition, and so on). This is the subscriber array. When a number of properties in a VM change (as the internal set method is mobilized), the evaluation function is executed to perform the other things together, thereby minimizing local refreshes of the view. The problem is that our pages are sometimes large and have many binding properties, which means that these intermediate-generated evaluation functions and objects will always be in each Subscriber array, consuming a lot of memory. If there is a waterfall stream or a timed refresh, this memory footprint will be larger and slower for the page to run. Therefore, it is necessary to consider the recovery of memory. Avalon the solution given, when a node is going out of the DOM tree, the evaluation function generated by its own or the underlying node's original binding properties will be removed from the subscriber array.
function notifysubscribers (accessor) {//Notifies subscribers dependent on this accessor to update themselves var list = Accessor[subscribers] if (list && List.length) {var args = Aslice.call (arguments, 1) for (var i = list.length, fn; fn = list[--i];) {var el = fn.element, remove if (El &&!avalon.contains (Ifsanctuary, EL)) {if (typeof El.sourceindex = = "Number") {//ie6-ie11 remove = El.sourceindex = = 0} else {remove =!avalon.contains (Root, EL)} if (
Remove) {//If it is not in the DOM tree List.splice (I, 1) log ("Debug:remove" + fn.name)
} if (typeof fn = = "function") {fn.apply (0, args)//force recalculate itself else if (fn.getter) {fn.handler.apply (FN, args)//Process Monitor array method} else {Fn.h Andler (fn.evaluator.apply (0, FN.args | | []), El, fn)}}}
The above is the implementation of this operation, the VM to be synchronized to the view must go through this method notifysubscribers. Each time it executes, it gets the element node on the evaluation function and then determines whether it is on the DOM tree. In ie6-11, we can determine whether the Sourceindex attribute is zero, and the standard browser can know by whether the root node contains the current element (the contains method needs to be compatible internally).
This column more highlights: http://www.bianceng.cnhttp://www.bianceng.cn/webkf/tools/
However, the emergence of ms-if to break this harmonious situation, to consider this binding actively move out of the DOM tree, but also to determine when this element is inserted back into the DOM tree. In a cyclic binding, the element node is dynamically generated in the beginning of the document fragment, which is even more troublesome. From 0.6-1.1, I've been in this nightmare. I used to have a timer, constantly polling whether the node is inserted into the DOM, inserted to start scanning it. Later, I discovered the incident of domnodeinserted, and made some optimizations for some advanced browsers. By 0.982, simply assume that they were not in the first place in the DOM, add a class name, prevent the move from moving out, and then bind the current VM list to the element, and then determine if the element is in the DOM tree (again polling operation). Then rewrite the cyclic binding section, after Ms-each, Ms-repeat, and so on, execute a callback, scan the current section, so you can eliminate polling operations. The next improvement is to make sure that when the loop is generated, the elements are concentrated in one document fragment, and then the whole DOM is inserted, and then the scan is done. In other words, it's always in the DOM tree for the first time. So you can eliminate the contains decision, ms-if code is greatly reduced. Now the ms-if is not the same, adding on-demand loading features. Its child element scans are controlled by its binding attributes and are useful for optimizing the performance of large pages.
The
batch generation and monitoring array implementations are complementary. Early monitoring is directly modified in the original array, so the original factory function is very large. Then directly put these to cover the function on an object, and then the factory method directly mix the line. Also simply connect all of the monitoring arrays to share these methods and save memory. In the implementation of the binding, there are many branches, what push, unshift, pop, shift, set, Reroder, splice, clear a lot of, that view refresh function is too bitter force. Later the operation of the array of in-depth analysis, found that all operations are undoubtedly doing the following operations, add elements, delete elements, rewrite the corresponding index value of elements, move elements to a location, directly replace elements. Then rewrite the method of monitoring the array, according to add. Del, index, move these four operations are combined (0.9.0) and then clear, because this operation is used for batch processing of an array or a child object. In these operations, the Notifysubscribers method is used to transfer the operation name and corresponding parameters to the view refresh function, which can be assigned to different branches for DOM processing. This is a big step in success. Inside actually also involves the generation of proxy VM is processing, so have the internal function of Createitemmodel, then appeared Ms-with, so they renamed Createwithmodel, Createeachmodel. The implementations of these two methods have also been improved, later renamed to Createeachproxy, Creatwithproxy, and the object pooling technique (Withmapper, 0.96) in Ms-with, which reuses all the proxy objects that are generated by using the same key value pairs.
To 0.9.8, secretly introducing a ms-repeat binding. The early reference object of Avalon was knockout, it requires two elements, a parent element as a container, a template for all nodes below it, or a virtual node (the real name is the two one after the annotation node) to delineate the scope of the function, the inside of those child points as templates. Because the annotation node will be confused on the ul,ol element of the ie6-8, it needs to be handled manually and the Avalon will not be more advanced. But in many occasions, always want to coat a parent node is very difficult, or do not, so moved to the angular. Angular ng-repeat only the loop element itself is a very good solution, plus it brought $first, $last, $remove and other good things, so Avalon began to imitate. However, this project is very difficult, and it has been staggering, and it was basically completed at 1.2. The question to be dealt with is how to get ms-repeat to traverse both the array and the object, the output order of the object's key-value pairs (the introduction of the data-with-sorted callback), the callback after the batch (Data-*-rendered callback), the rollback mechanism ( Rollback function), how to determine that a child element has been rendered (you need to add a tag on the element, and then execute a callback at scanattr). Callback is a colleague in doing private person project proposed, initially no parameters, now can be explicitly add, Del, index and other operations. The Generation agent VM and the binding tag are later abstracted into a shimcontroller to achieve BULK INSERT and batch processing. The object pool (renamed Withproxypool) is also greatly optimized, which generates all the key-value pair proxy VMS at the outset and is no longer judged in the evaluation function. And the VM adds a withproxycount for optimization.
The internal methods and objects involved in the current batch processing
Createwithproxy proxy VM When creating a looping object
Createeachproxy proxy VM When creating a cyclic array
Updatewithproxy a proxy VM that updates a key value pair
Withproxypool Createwithproxy generated objects are unified here to manage to prevent duplicate generation
Removeview Bulk Remove a bunch of nodes
Getlocatednode Locate the location you want to insert
Shimcontroller for Ms-each, Ms-with, ms-repeat to cycle the elements of outsourcing a msloop temporary node, ms-controller the value of the proxy VM $id, but also the implementation of the bulk insert interpolation to remove the temporary node key
Removefromsanctuary will move out of the DOM tree through the ms-if to the Ifsanctuary element node for garbage collection
Querycomments to get all the annotation nodes under an element node or document fragment object
Iteratorcallback performs data-*-rendered callbacks through it
The last one is the hardest one, at least not yet, only in constant improvement, and this is the design of UI bindings. Before there is a binding called Ms-ui, has died. Now the ms-widget is still not good enough. Sometimes I want to refer to the way angular, but I think it adds too many inexplicable symbols. But mostly because my frame is very indulgent to the user and doesn't like the design of that reconfiguration. But what's left of the present is that it has a major flaw, no lifecycle management. This has been exposed in the project, requiring the user to define a destroy method and manually destroy it. I think that's part of the framework. For the next few weeks, I've been working on this improvement, hoping to get rid of the pain point.
Finally, summarize:
VM implementation, how to build a synchronization mechanism with V.
Ms-if,ng-if, data-bind= "if:xxx" such as the insertion of the removal of the binding, will be interrupted before the suspense has been swept to the end of the idea, before the good life cycle management will go awry!
Ms-each, Ms-repeat, ng-repeat,data-bind=, a batch-generated binding such as "foreach:xxx", which is most likely to cause performance problems and needs to define its scope
Ms-widget, <widget></widget> Such a conversion element is the binding of a control, which is also the most complex and troublesome binding that requires a holistic design view.
Of course, there are a lot of trouble with people who have just come into contact with this field, such as how to deal with a lot of compatibility problems without using jquery, how to write a parser to resolve the value of binding attributes, loaders, routers, animation engines and so on a lot of ancillary facilities ... This will be your own blessing, good for it, but across this hurdle, you are another level of character!