Home > Web Front-end > JS Tutorial > Detailed explanation of compile and link functions in angularjs instructions_AngularJS

Detailed explanation of compile and link functions in angularjs instructions_AngularJS

WBOY
Release: 2016-05-16 16:28:54
Original
1367 people have browsed it

Usually when people use instructions in ng, the most commonly used link function is the link attribute. The following article will tell you the usage and differences of complie, pre-link, and post-link.

The directives in angularjs are very magical, allowing you to create very semantic and highly reusable components. It can be understood as the pioneer of web components.

There are many articles and related books on how to use instructions on the Internet. Compared with each other, there are few introductions to the difference between compile and link, let alone pre-link and post-link.

Most tutorials simply say that compile will be used internally in ng, and it is recommended that you only use the link attribute. This is the case in most instruction examples

This is very unfortunate, because correctly understanding the difference between these functions will improve your understanding of the internal working mechanism of ng and help you develop better custom instructions.

So follow me and read the following content step by step to understand what these functions are and when they should be used

This article assumes that you already have a certain understanding of directives. If not, it is strongly recommended that you read this articleAngularJS developer guide section on directives

How to process instructions in NG

Before starting the analysis, let us first take a look at how instructions are processed in ng.

When the browser renders a page, it essentially reads the HTML tag, then creates the dom node, and broadcasts an event to us after the dom tree is created.

When you use the script tag to load the ng application code in the page, ng listens to the dom completion event above and looks for elements with the ng-app attribute.

When such an element is found, ng starts processing dom from the starting point of this element, so if ng-app is added to the html element, ng will start processing dom from the html element.

From this starting point, ng starts to recursively search all sub-elements that comply with the instruction rules defined in the application.

How ng handles instructions actually depends on the object attributes when it is defined. You can define a compile or a link function, or use pre-link and post-link functions instead of link.

So what’s the difference between these functions? Why should you use it? And when should you use it?

With these questions, follow me step by step to answer these mysteries

A piece of code

To explain the difference between these functions, I will use a simple and easy-to-understand example below

1. If you have any questions, please don’t hesitate to add your comments below.

Look at the following html tag code

Copy code The code is as follows:


                                                                                                                                                                                            Hello
                                               
                                                                                     




Then a piece of js code

Copy code The code is as follows:

var app = angular.module('plunker', []);

    function createDirective(name){
      return function(){
        return {
          restrict: 'E',
          compile: function(tElem, tAttrs){
            console.log(name ': compile');
            return {
              pre: function(scope, iElem, iAttrs){
                console.log(name ': pre link');
              },
              post: function(scope, iElem, iAttrs){
                console.log(name ': post link');
              }
            }
          }
        }
      }
    }

    app.directive('levelOne', createDirective('levelOne'));
    app.directive('levelTwo', createDirective('levelTwo'));
    app.directive('levelThree', createDirective('levelThree'));

结果非常简单:让ng来处理三个嵌套指令,并且每个指令都有自己的complile,pre-link,post-link函数,每个函数都会在控制台里打印一行东西来标识自己.

这个例子能够让我们简单的了解到ng在处理指令时,内部的流程

代码输出

下面是一个在控制台输出结果的截图

如果想自己试一下这个例子的话,请点击this plnkr,然后在控制台查看结果.

分析代码

第一个要注意的是这些函数的调用顺序:

复制代码 代码如下:

 // COMPILE PHASE
    // levelOne:    compile function is called
    // levelTwo:    compile function is called
    // levelThree:  compile function is called

    // PRE-LINK PHASE
    // levelOne:    pre link function is called
    // levelTwo:    pre link function is called
    // levelThree:  pre link function is called

    // POST-LINK PHASE (Notice the reverse order)
    // levelThree:  post link function is called
    // levelTwo:    post link function is called
    // levelOne:    post link function is called

这个例子清晰的显示出了ng在link之前编译所有的指令,然后link要又分为了pre-link与post-link阶段.

注意下,compile与pre-link的执行顺序是依次执行的,但是post-link正好相反.

所以上面已经明确标识出了不同的阶段,但是compile与pre-link有什么区别呢,都是相同的执行顺序,为什么还要分成两个不同的函数呢?

DOM

为了挖的更深一点,让我们简单的修改一下上面的代码,它也会在各个函数里打印参数列表中的element变量

复制代码 代码如下:

var app = angular.module('plunker', []);

    function createDirective(name){
      return function(){
        return {
          restrict: 'E',
          compile: function(tElem, tAttrs){
            console.log(name ': compile => ' tElem.html());
            return {
              pre: function(scope, iElem, iAttrs){
                console.log(name ': pre link => ' iElem.html());
              },
              post: function(scope, iElem, iAttrs){
                console.log(name ': post link => ' iElem.html());
              }
            }
          }
        }
      }
    }

    app.directive('levelOne', createDirective('levelOne'));
    app.directive('levelTwo', createDirective('levelTwo'));
    app.directive('levelThree', createDirective('levelThree'));

Pay attention to the output in console.log. Apart from outputting the original html markup, there is basically no other change.

This should deepen our understanding of the context of these functions.

Run the code again and see

Output

The following is a screenshot of the console output

If you still want to run it yourself to see the effect, you can click this plnkr, and then view the output results in the console.

Observe

The result of outputting dom can reveal some interesting things: the dom content is different in the compile and pre-link functions

So what happened?

Compile

We already know that ng starts processing the dom when it finds that the dom construction is completed.

So when ng is traversing the dom, it encounters the level-one element and learns from its definition that it needs to execute some necessary functions

Because the compile function is defined in the command object of the level-one directive, it will be called and passed an element object as its parameter

If you look carefully, you will see that when the browser creates this element object, it is still the original html markup

1. In ng, the original dom is usually used to identify the template element, so I used the tElem name when defining the compile function parameters. This variable points to the template element.

Once the compile function in the levelone directive is run, ng will recursively traverse its DOM nodes in depth, and then repeat these operations on level-two and level-three.

Post-link

Before we dive into the pre-link function, let’s take a look at the post-link function.

2. If you only use one link function when defining the instruction, then ng will treat this function as post-link, so we need to discuss this function first
After ng has traversed all the DOM and run all the compile functions, it calls the associated post-link function in reverse.

The dom now starts to reverse and execute the post-link function. Therefore, this reverse call seemed a bit strange before, but it actually makes perfect sense.

When running a command post-link that contains sub-commands, the reverse post-link rule can ensure that the post-link of its sub-commands has already been run.

So, when running the post-link function of the level-one instruction, we can ensure that the post-links of level-two and level-three have actually been run.

This is why people think post-link is the safest or default place to write business logic.

But why is the element here different from the one in compile?

Once ng calls the compile function of the instruction, it will create an element instance object of the template element and provide it with a scope object. This scope may be a new instance, or it may already exist, or it may be a subscope. It may also be an independent scope, which all depends on the scope attribute value in the instruction definition object

So when linking occurs, this instance element and scope object are already available, and are passed as parameters to the parameter list of the post-link function by ng.

1. Personally, I always use the iElem name to define the parameters of a link function, and it points to the element instance

So the element parameter object of the post-link (pre-link) function is an element instance rather than a template element.

So the output in the above example is different

Pre-link

When writing a post-link function, you can ensure that when the post-link function is executed, the post-link functions of all its child instructions have already been executed.

In most cases, it can do better, so we usually use it to write instruction codes.

However, ng provides us with an additional hook mechanism, which is the pre-link function, which ensures that some other code is run before the post-link functions of all sub-instructions are executed.

This sentence is worthy of repeated consideration

The pre-link function is guaranteed to be executed before the post-link of the element instance and all its sub-instructions is run.

So it makes sense to execute the post-link function in reverse, and it itself is the original sequential execution of the pre-link function

This also means that the pre-link function runs before the pre-link functions of all its sub-instructions, so the complete reason is:

The pre-link function of an element is guaranteed to be executed before the post-link and pre-link of all its sub-commands are executed. See the figure below:

Review

If we look back at the original output above, we can clearly recognize what happened:

Copy code The code is as follows:

    // HERE THE ELEMENTS ARE STILL THE ORIGINAL TEMPLATE ELEMENTS

    // COMPILE PHASE
    // levelOne:    compile function is called on original DOM
    // levelTwo:    compile function is called on original DOM
    // levelThree:  compile function is called on original DOM

    // AS OF HERE, THE ELEMENTS HAVE BEEN INSTANTIATED AND
    // ARE BOUND TO A SCOPE
    // (E.G. NG-REPEAT WOULD HAVE MULTIPLE INSTANCES)

    // PRE-LINK PHASE
    // levelOne:    pre link function is called on element instance
    // levelTwo:    pre link function is called on element instance
    // levelThree:  pre link function is called on element instance

    // POST-LINK PHASE (Notice the reverse order)
    // levelThree:  post link function is called on element instance
    // levelTwo:    post link function is called on element instance
    // levelOne:    post link function is called on element instance

概要

回顾上面的分析我们可以描述一下这些函数的区别以及使用情况:

Compile 函数

使用compile函数可以改变原始的dom(template element),在ng创建原始dom实例以及创建scope实例之前.

可以应用于当需要生成多个element实例,只有一个template element的情况,ng-repeat就是一个最好的例子,它就在是compile函数阶段改变原始的dom生成多个原始dom节点,然后每个又生成element实例.因为compile只会运行一次,所以当你需要生成多个element实例的时候是可以提高性能的.

template element以及相关的属性是做为参数传递给compile函数的,不过这时候scope是不能用的:

下面是函数样子:

复制代码 代码如下:

/**
    * Compile function
    *
    * @param tElem - template element
    * @param tAttrs - attributes of the template element
   */
    function(tElem, tAttrs){

        // ...

    };

Pre-link 函数

使用pre-link函数可以运行一些业务代码在ng执行完compile函数之后,但是在它所有子指令的post-link函数将要执行之前.

scope对象以及element实例将会做为参数传递给pre-link函数:

下面是函数样子:

复制代码 代码如下:

/**
    * Pre-link function
    *
    * @param scope - scope associated with this istance
    * @param iElem - instance element
    * @param iAttrs - attributes of the instance element
   */
    function(scope, iElem, iAttrs){

        // ...

    };

Post-link 函数

使用post-link函数来执行业务逻辑,在这个阶段,它已经知道它所有的子指令已经编译完成并且pre-link以及post-link函数已经执行完成.

这就是被认为是最安全以及默认的编写业务逻辑代码的原因.

scope实例以及element实例做为参数传递给post-link函数:

下面是函数样子:

复制代码 代码如下:

/**
    * Post-link function
    *
    * @param scope - scope associated with this istance
    * @param iElem - instance element
    * @param iAttrs - attributes of the instance element
   */
    function(scope, iElem, iAttrs){

        // ...

    };

Summary

Now you should have a clear understanding of the differences between compile, pre-link, and post-link functions.

If you haven’t, and you are a serious ng developer, then I strongly recommend you to read this article again until you understand it

It is very important to understand these concepts, which can help you understand how ng’s native instructions work, and can also help you optimize your own custom instructions.

If you still have questions, you are welcome to add your questions in the comments below

I will analyze the other two issues in the directive in the future:

1. How does the directive use the transclusion attribute work?
2. How are the controller functions of the instructions related?

Finally, if you find anything wrong with this article, please send me a comment in time

Thank you!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template