Skip to content

Commit 994685c

Browse files
committed
Merge remote-tracking branch 'upstream/master'
# Conflicts: # src/v2/api/index.md # src/v2/guide/components-custom-events.md # src/v2/guide/computed.md # src/v2/guide/deployment.md # src/v2/guide/installation.md # src/v2/guide/render-function.md # src/v2/style-guide/index.md # themes/vue/layout/partials/sidebar.ejs Signed-off-by: MachinisteWeb <[email protected]>
2 parents e8b46f4 + b537945 commit 994685c

19 files changed

+495
-87
lines changed

src/images/memory-leak-example.png

223 KB
Loading

src/images/search-by-algolia.png

2.81 KB
Loading

src/v2/api/index.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ type: api
255255

256256
- **Utilisation :**
257257

258-
Assigne une propriété à un objet cible. Si l'objet est réactif, cette méthode s'assure que la propriété est créée en tant que propriété réactive et déclenche les mises à jour de la vue. Ceci est principalement utilisé pour passer outre la limitation de Vue qui est de ne pas pouvoir détecter automatiquement l'ajout de nouvelles propriétés.
258+
Assigne une propriété à un objet réactif, s'assurant que la nouvelle propriété soit également réactive de manière à déclencher une nouvelle mise à jour de la vue. Ceci doit être utilisé pour les nouvelles propriétés d'objets réactifs car Vue ne peut pas détecter normalement les ajouts de propriétés (par ex. `this.myObject.newProperty = 'bonjour'`).
259259

260260
<p class="tip">L'objet ne peut pas être une instance de Vue, ou l'objet de données à la racine d'une instance de Vue.</p>
261261

@@ -1023,21 +1023,23 @@ type: api
10231023
- un objet où les clés sont les noms des liaisons locales et où les valeurs sont :
10241024
- les clés (`String` ou `Symbol`) à rechercher dans les injections disponibles, ou
10251025
- un objet où :
1026-
- la propriété `name` est la clé (`String` ou `Symbol`) à rechercher dans les injections disponibles, et
1026+
- la propriété `from` est la clé (`String` ou `Symbol`) à rechercher dans les injections disponibles, et
10271027
- la propriété `default` est utilisé comme valeur de substitution.
10281028
10291029
> Note : les liaisons `provide` et `inject` ne sont PAS réactives. C'est intentionnel. Cependant, si vous passez un objet observé, les propriétés sur cet objet resteront réactives.
10301030
10311031
- **Exemple :**
10321032
10331033
``` js
1034+
// parent component providing 'foo'
10341035
var Provider = {
10351036
provide: {
10361037
foo: 'bar'
10371038
},
10381039
// ...
10391040
}
10401041

1042+
// le composant enfant injectant 'foo'
10411043
var Enfant = {
10421044
inject: ['foo'],
10431045
created () {
@@ -2177,7 +2179,7 @@ Used to denote a `<template>` element as a scoped slot, which is replaced by [`s
21772179

21782180
### is
21792181

2180-
- **Attend comme valeur :** `string`
2182+
- **Attend comme valeur :** `string | Object (un objet d'options de composant)`
21812183

21822184
Utilisé pour les [composants dynamiques](../guide/components.html#Composants-dynamiques) et pour contourner les [limitations des templates dans le DOM](../guide/components.html#Limitations-de-l’analyse-d’un-template-a-partir-du-DOM).
21832185

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
---
2+
title: Avoiding Memory Leaks
3+
type: cookbook
4+
order: 10
5+
---
6+
## Introduction
7+
8+
If you are developing applications with Vue, then you need to watch out for memory leaks. This issue is especially important in Single Page Applications (SPAs) because by design, users should not have to refresh their browser when using an SPA, so it is up to the Javascript application to clean up components and make sure that garbage collection takes place as expected.
9+
10+
Memory leaks in Vue applications do not typically come from Vue itself, rather they can happen when incorporating other libraries into an application.
11+
12+
## Simple Example
13+
14+
The following example shows a memory leak caused by using the [Choices.js](https://github.com/jshjohnson/Choices) library in a Vue component and not properly cleaning it up. Later, we will show how to remove the Choices.js footprint and avoid the memory leak.
15+
16+
In the example below, we load up a select with a lot of options and then we use a show/hide button with a [v-if](/v2/guide/conditional.html) directive to add it and remove it from the virtual DOM. The problem with this example is that the `v-if` directive removes the parent element from the DOM, but we did not clean up the additional DOM pieces created by Choices.js, causing a memory leak.
17+
18+
```html
19+
<link rel='stylesheet prefetch' href='https://joshuajohnson.co.uk/Choices/assets/styles/css/choices.min.css?version=3.0.3'>
20+
<script src='https://joshuajohnson.co.uk/Choices/assets/scripts/dist/choices.min.js?version=3.0.3'></script>
21+
22+
<div id="app">
23+
<button v-if="showChoices" @click="hide">Hide</button>
24+
<button v-if="!showChoices" @click="show">Show</button>
25+
<div v-if="showChoices">
26+
<select id="choices-single-default"></select>
27+
</div>
28+
</div>
29+
```
30+
```js
31+
new Vue({
32+
el: "#app",
33+
data: function () {
34+
return {
35+
showChoices: true
36+
}
37+
},
38+
mounted: function () {
39+
this.initializeChoices()
40+
},
41+
methods: {
42+
initializeChoices: function () {
43+
let list = []
44+
// lets load up our select with many choices
45+
// so it will use a lot of memory
46+
for (let i = 0; i < 1000; i++) {
47+
list.push({
48+
label: "Item " + i,
49+
value: i
50+
})
51+
}
52+
new Choices("#choices-single-default", {
53+
searchEnabled: true,
54+
removeItemButton: true,
55+
choices: list
56+
})
57+
},
58+
show: function () {
59+
this.showChoices = true
60+
this.$nextTick(() => {
61+
this.initializeChoices()
62+
})
63+
},
64+
hide: function () {
65+
this.showChoices = false
66+
}
67+
}
68+
})
69+
```
70+
To see this memory leak in action, open this [CodePen example](https://codepen.io/freeman-g/pen/qobpxo) using Chrome and then open the Chrome Task Manager. To open the Chrome Task Manager on Mac, choose Chrome Top Navigation > Window > Task Manager or on Windows, use the Shift+Esc shortcut. Now, click the show/hide button 50 or so times. You should see the memory usage in the Chrome Task Manager increase and never be reclaimed.
71+
72+
![Memory Leak Example](/images/memory-leak-example.png)
73+
74+
## Resolving the Memory Leak
75+
76+
In the above example, we can use our `hide()` method to do some clean up and solve the memory leak prior to removing the select from the DOM. To accomplish this, we will keep a property in our Vue instance’s data object and we will use the [Choices API’s](https://github.com/jshjohnson/Choices) `destroy()` method to perform the clean up.
77+
78+
Check the memory usage again with this [updated CodePen example](https://codepen.io/freeman-g/pen/mxWMor).
79+
80+
```js
81+
new Vue({
82+
el: "#app",
83+
data: function () {
84+
return {
85+
showChoices: true,
86+
choicesSelect: null
87+
}
88+
},
89+
mounted: function () {
90+
this.initializeChoices()
91+
},
92+
methods: {
93+
initializeChoices: function () {
94+
let list = []
95+
for (let i = 0; i < 1000; i++) {
96+
list.push({
97+
label: "Item " + i,
98+
value: i
99+
})
100+
}
101+
// Set a reference to our choicesSelect in our Vue instance's data object
102+
this.choicesSelect = new Choices("#choices-single-default", {
103+
searchEnabled: true,
104+
removeItemButton: true,
105+
choices: list
106+
})
107+
},
108+
show: function () {
109+
this.showChoices = true
110+
this.$nextTick(() => {
111+
this.initializeChoices()
112+
})
113+
},
114+
hide: function () {
115+
// now we can use the reference to Choices to perform clean up here
116+
// prior to removing the elements from the DOM
117+
this.choicesSelect.destroy()
118+
this.showChoices = false
119+
}
120+
}
121+
})
122+
```
123+
124+
## Details about the Value
125+
126+
Memory management and performance testing can easily be neglected in the excitement of shipping quickly, however, keeping a small memory footprint is still important to your overall user experience.
127+
128+
Consider the types of devices your users may be using and what their normal flow will be. Could they use memory constrained laptops or mobile devices? Do your users typically do lots of in-application navigation? If either of these are true, then good memory management practices can help you avoid the worst case scenario of crashing a user’s browser. Even if neither of these are true, you can still potentially have degradation of performance over extended usage of your app if you are not careful.
129+
130+
## Real-World Example
131+
132+
In the above example, we used a `v-if` directive to illustrate the memory leak, but a more common real-world scenario happens when using [vue-router](https://router.vuejs.org/en/) to route to components in a Single Page Application.
133+
134+
Just like the `v-if` directive, `vue-router` removes elements from the virtual DOM and replaces those with new elements when a user navigates around your application. The Vue `beforeDestroy()` [lifecycle hook](/v2/guide/instance.html#Lifecycle-Diagram) is a good place to solve the same sort of issue in a `vue-router` based application.
135+
136+
We could move our clean up into the `beforeDestroy()` hook like this:
137+
138+
```js
139+
beforeDestroy: function () {
140+
this.choicesSelect.destroy()
141+
}
142+
```
143+
144+
## Alternative Patterns
145+
146+
We have discussed managing memory when removing elements, but what if you intentionally want to preserve state and keep elements in memory? In this case, you can use the built-in component [keep-alive](/v2/api/#keep-alive).
147+
148+
When you wrap a component with `keep-alive`, its state will be preserved and therefore kept in memory.
149+
150+
```html
151+
<button @click="show = false">Hide</button>
152+
<keep-alive>
153+
<!-- my-component will be intentionally kept in memory even when removed -->
154+
<my-component v-if="show"></my-component>
155+
</keep-alive>
156+
```
157+
This technique can be useful to improve user experience. For example, imagine a user starts entering comments into a text input and then decides to navigate away. If the user then navigated back, their comments would still be preserved.
158+
159+
Once you use keep-alive, then you have access to two more lifecycle hooks: `activated` and `deactivated`. If you do want to clean up or change data when a keep-alive component is removed, you can do so in the `deactivated` hook.
160+
161+
```js
162+
deactivated: function () {
163+
// remove any data you do not want to keep alive
164+
}
165+
```
166+
167+
## Wrapping Up
168+
169+
Vue makes it very easy to develop amazing, reactive Javascript applications, but you still need to be careful about memory leaks. These leaks will often occur when using additional 3rd Party libraries that manipulate the DOM outside of Vue. Make sure to test your application for memory leaks and take appropriate steps to clean up components where necessary.

src/v2/guide/components-custom-events.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ Vue.component('base-input', {
128128
})
129129
```
130130

131-
À présent, le composant `<base-input>` est une **enveloppe complètement transparente**, c'est-à-dire qu'il peut être utilisé comme un élément `<input>` normal : tous les mêmes attributs et écouteurs d'événements fonctionneront.
131+
À présent, le composant `<base-input>` est une **enveloppe complètement transparente**, c'est-à-dire qu'il peut être utilisé comme un élément `<input>` normal : tous les mêmes attributs et écouteurs d'événements fonctionneront, sans le modificateur `.native`.
132132

133133
## Modificateur `.sync`
134134

src/v2/guide/computed.md

Lines changed: 41 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -215,37 +215,35 @@ var watchExampleVM = new Vue({
215215
// à chaque fois que la question change, cette fonction s'exécutera
216216
question: function (newQuestion, oldQuestion) {
217217
this.answer = "J'attends que vous arrêtiez de taper..."
218-
this.getAnswer()
218+
this.debouncedGetAnswer()
219219
}
220220
},
221-
methods: {
221+
created: function () {
222222
// _.debounce est une fonction fournie par lodash pour limiter la fréquence
223223
// d'exécution d'une opération particulièrement couteuse.
224224
// Dans ce cas, nous voulons limiter la fréquence d'accès à
225225
// yesno.wtf/api, en attendant que l'utilisateur ait complètement
226226
// fini de taper avant de faire la requête ajax. Pour en savoir
227-
// plus sur la fonction _.debounce (et sa cousine
228-
// _.throttle), visitez : https://lodash.com/docs#debounce
229-
getAnswer: _.debounce(
230-
function () {
231-
if (this.question.indexOf('?') === -1) {
232-
this.answer = "Les questions contiennent généralement un point d'interrogation. ;-)"
233-
return
234-
}
235-
this.answer = 'Je réfléchis...'
236-
var vm = this
237-
axios.get('https://yesno.wtf/api')
238-
.then(function (response) {
239-
vm.answer = _.capitalize(response.data.answer)
240-
})
241-
.catch(function (error) {
242-
vm.answer = "Erreur ! Impossible d'accéder à l'API." + error
243-
})
244-
},
245-
// C'est le nombre de millisecondes que nous attendons
246-
// pour que l’utilisateur arrête de taper.
247-
500
248-
)
227+
// plus sur la fonction `_.debounce` (et sa cousine
228+
// `_.throttle`), visitez : https://lodash.com/docs#debounce
229+
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
230+
},
231+
methods: {
232+
getAnswer: function () {
233+
if (this.question.indexOf('?') === -1) {
234+
this.answer = "Les questions contiennent généralement un point d'interrogation. ;-)"
235+
return
236+
}
237+
this.answer = 'Je réfléchis...'
238+
var vm = this
239+
axios.get('https://yesno.wtf/api')
240+
.then(function (response) {
241+
vm.answer = _.capitalize(response.data.answer)
242+
})
243+
.catch(function (error) {
244+
vm.answer = "Erreur ! Impossible d'accéder à l'API." + error
245+
})
246+
}
249247
}
250248
})
251249
</script>
@@ -273,28 +271,28 @@ var watchExampleVM = new Vue({
273271
watch: {
274272
question: function (newQuestion, oldQuestion) {
275273
this.answer = "J'attends que vous arrêtiez de taper..."
276-
this.getAnswer()
274+
this.debouncedGetAnswer()
277275
}
278276
},
277+
created: function () {
278+
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
279+
},
279280
methods: {
280-
getAnswer: _.debounce(
281-
function () {
282-
var vm = this
283-
if (this.question.indexOf('?') === -1) {
284-
vm.answer = "Les questions contiennent généralement un point d'interrogation. ;-)"
285-
return
286-
}
287-
vm.answer = 'Je réfléchis...'
288-
axios.get('https://yesno.wtf/api')
289-
.then(function (response) {
290-
vm.answer = _.capitalize(response.data.answer.replace(/yes/g, 'oui').replace(/no/g, 'non'))
291-
})
292-
.catch(function (error) {
293-
vm.answer = "Erreur ! Impossible d'accéder à l'API." + error
294-
})
295-
},
296-
500
297-
)
281+
getAnswer: function () {
282+
if (this.question.indexOf('?') === -1) {
283+
this.answer = "Les questions contiennent généralement un point d'interrogation. ;-)"
284+
return
285+
}
286+
this.answer = 'Je réfléchis...'
287+
var vm = this
288+
axios.get('https://yesno.wtf/api')
289+
.then(function (response) {
290+
vm.answer = _.capitalize(response.data.answer)
291+
})
292+
.catch(function (error) {
293+
vm.answer = "Erreur ! Impossible d'accéder à l'API." + error
294+
})
295+
}
298296
}
299297
})
300298
</script>

src/v2/guide/deployment.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@ Quand vous utilisez un outil de build comme webpack ou Browserify, le mode produ
1818

1919
#### webpack
2020

21-
Utiliser le plugin [DefinePlugin](https://webpack.js.org/plugins/define-plugin/) de webpack pour indiquer un environnement de production, ainsi les blocs d'avertissements seront ignorés par UglifyJS pendant la minification. Un exemple de configuration :
21+
Dans webpack 4+, vous pouvez utiliser l'option `mode` :
22+
23+
``` js
24+
module.exports = {
25+
mode: 'production'
26+
}
27+
```
28+
29+
Mais dans webpack 3 et précédent, vous devez utiliser la fonction [DefinePlugin](https://webpack.js.org/plugins/define-plugin/) :
2230

2331
``` js
2432
var webpack = require('webpack')
@@ -29,13 +37,12 @@ module.exports = {
2937
// ...
3038
new webpack.DefinePlugin({
3139
'process.env': {
32-
NODE_ENV: '"production"'
40+
NODE_ENV: JSON.stringify('production')
3341
}
3442
})
3543
]
3644
}
3745
```
38-
3946
#### Browserify
4047

4148
- Lancer votre commande d'empaquetage avec la variable d'environnement `NODE_ENV` assignée à `"production"`. Cela indique à `vueify` d'éviter d'inclure le code utilisé pour le rechargement à chaud ou lié au développement.

0 commit comments

Comments
 (0)