17

Vue.js Internals  -  What’s involved in a method call?

 4 years ago
source link: https://www.tuicool.com/articles/vyEv6jb
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
JRVZRb7.png!webfa6ba2f.png!web

Vue is Javascript magic . Vue provides tooling to rapidly create interactive user interfaces quickly. It does this with the concept of reusable components that renders and updates html based on that component’s data . In development circles, this is called two-way data binding . Make a change to the data and watch the HTML update automatically. Have an HTML input element? Tell Vue to tie the form into the data and watch the data change as you input text. See? Magic .

Vue components also have methods that you can call. These methods are more commonly used as event handlers. Want to run code when a button is clicked? Assign a function in your Vue component as it’s handler. Inside your method, you can manipulate the component’s data and then watch again how the html changes. It’s the circle of life.

Here is a an HTML snippet that might be in your component’s html.

m6ryEru.jpg!web

And this could be your simple Vue application

m6ryEru.jpg!web

Notice how you create a function called increment inside a property called methods . You aren’t using this property name when referencing the method. And when you attempt to call this method outside of the component, you don’t use the methods property at all.

m6ryEru.jpg!web

So how are we able to call that method without referencing the methods property? How does Vue do this?

If we were to inspect the Vue instance ‘ app ’ directly in Chrome DevTools, we’ll see a very rich object like below.

FJzqqaF.png!web6ZN36bU.png!web

This object has a great deal of behavior built into it. You can see properties and functions that relate to watchers, lifecycle events and more. In this object, you can also see an increment function. This increment function has additional properties which include TargetFunction , BoundThis and BoundArgs . This tells us something interesting. The secret is that the increment function isn’t our increment function at all. It’s a wrapper that points to our increment function. How did Vue.JS do this?

The internal building of your Vue instance

When we instantiate a new Vue instance using new Vue({…}) , we are passing in an options object that contains what will be our app’s state and behavior. What we get as a result is Vue’s composition of a new object that wraps all the dynamic binding and behavior around our intentions. Let’s take a look at the Vue constructor’s file in Vue’s source code.

m6ryEru.jpg!web

When we call the Vue constructor, it internally calls the _init function on the new Vue object, passing in our options object. This _init function is defined in the initMixin . Inside the _init function, Vue begins to build out the wrapped behavior. Inside this nest of calls is an initMethods function call which occurs when we have a methods property in our options object. Let’s take a look at the initMethods function.

m6ryEru.jpg!web

This function is called with a vm argument which points to the new Vue instance that is being built. The methods argument contains all our method definitions, ready to be assigned to our instance.

If all error checking looks good, including making sure we don’t have a function name the same as a data property, then we call the bind function, passing in our own function declaration and a reference to the new Vue instance as vm . Let’s take a look at Vue’s bind function declaration.

m6ryEru.jpg!web

We can see in the utility file that the bind function will use a custom bind implementation for Javascript environments that do not have a native Function.prototype.bind function. Otherwise, it will utilize the built-in Function.prototype.bind function, ensuring the this context inside the function will point to our new Vue instance.

Going back to our initMethods function, the code, in the context of our example, could be seen as below.

m6ryEru.jpg!web

The bind function that belongs to the Function.prototype returns a new function that, when called, will have the this keyword set to the argument passed into bind. The result of the bind call is then assigned to our new Vue instance using bracket notation .More information about the Function.prototype.bind function can be found at Mozilla’s Web Developer Documentation.

Once our Vue object is created and returned by the Vue constructor, the final object has a increment property which references the new Function returned by the bind call. This is how your function can utilize the this keyword which now properly references the Vue component it belongs to.

What about performance?

When you call the increment method on the new Vue instance we created, you’re actually calling the Function that was prepared by the bind call. Every Javascript engine does the internal implementation of binding differently and there are performance differences between browsers. In recent versions of Chrome, there is no perceivable difference when the v8 engine optimizes your code. However, in other browsers such as Microsoft Edge and Firefox, the performance difference of bound functions and non-bound functions can be significant. You can view the results of these tests and run them yourself using the following jsPerf test.

uumaEvI.png!webnMzmEjy.png!web
jsPerf tests showing results of Microsoft Edge (shown as Chrome 64), recent versions of Google Chrome and Firefox 66.0

The latest version of Microsoft Edge identifies as Chrome 64 in jsPerf charts. You can see significant differences in performance of calling functions that are bound using Function.prototype.bind. Recent versions of Chrome can optimize around this if it understands what you’re doing.

Why does this matter?

It probably doesn’t matter to you. Vue.js is magical when you don’t need to consider the internals. Just get up and use it. The potential performance overhead involved in calling a method also probably doesn’t matter to you since the interactions inside Vue.js does not need to be highly performance driven to provide a rich interactive user experience.

Why this matters to me

I am currently building a Nintendo emulator written in Javascript with Vue.js. This requires everything to be as fast as possible. Every wrapped behavior in Vue.js comes with a performance cost and I find myself having to move more of the emulator behavior outside of Vue.js to achieve the speeds necessary.

Now we know that the magic comes at a price.

Follow my development of my 8–Bit Nintendo emulator written in Javascript with Vue.js by following my code repository.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK