предисловие
В Vue опция данных — это хорошо: вбрасывая данные, вы можете читать данные в данных через это в любом месте компонента Vue. Но чтобы не злоупотреблять этим, чтобы читать данные в данных, что касается того, где избежать злоупотребления, и к каким последствиям это приведет, этот столбец будет раскрываться один за другим.
1. Процесс чтения данных в данных с этим
В исходном коде Vue данные в data будут добавлены с помощью функции получения и функции установки, чтобы преобразовать их в отзывчивые. Код функции геттера выглядит следующим образом:
function reactiveGetter() {
var value = getter ? getter.call(obj) : val;
if (Dep.target) {
dep.depend();
if (childOb) {
childOb.dep.depend();
if (Array.isArray(value)) {
dependArray(value);
}
}
}
return value
}
Когда данные в data читаются с этим, будет запущена функция получения, в которойvar value = getter ? getter.call(obj) : val;
Выполнить после получения значенияreturn value
, для достижения цели чтения данных.
Но есть и промежуточный фрагмент кода, в котором зависимости собираются с помощью ряда сложных логических операций. Как собирать зависимости здесь не рассказывается, если вы хотите узнать больше, вы можете прочитатьэтот столбец. Здесь вам нужно только знать, что зависимости будут собраны, когда существует Dep.target.
Здесь можно сделать вывод, когда существует Dep.target, используйте его для чтения данных в данных для сбора зависимостей. Если вы злоупотребите этим для чтения данных в данных, зависимости будут собираться повторно, что приведет к проблемам с производительностью.
2. Когда существует Dep.target?
Dep.target назначается зависимостями. Зависимость также известна как Наблюдатель (слушатель) или подписчик. В Vue есть три типа зависимостей, два из которых очень распространены, а именно watch (слушатель) и вычисляемый (вычисляемое свойство). Существует также скрытая зависимость, Rendering Watcher, которая создается во время первого рендеринга шаблона.
Dep.target назначается при создании зависимости, а зависимость создается с помощью конструктора Watcher.
function Watcher(vm, expOrFn, cb, options, isRenderWatcher) {
//...
if (typeof expOrFn === 'function') {
this.getter = expOrFn;
} else {
this.getter = parsePath(expOrFn);
}
this.value = this.lazy ? undefined : this.get();
};
Watcher.prototype.get = function get() {
pushTarget(this);
try {
value = this.getter.call(vm, vm);
} catch (e) {
}
return value
};
Dep.target = null;
var targetStack = [];
function pushTarget(target) {
targetStack.push(target);
Dep.target = target;
}
Метод экземпляра будет выполнен в конце конструктора Watcherget
, в методе экземпляраget
выполнить вpushTarget(this)
Назначен Dep.target в .
Зависимость создается при первом рендеринге страницы или компонента Vue, поэтому проблема с производительностью должна заключаться в медленном рендеринге в первый раз.
3. Где злоупотреблять этим, чтобы читать данные в данных
Выполнение этих кодов, которые злоупотребляют этим для чтения данных в данных, когда существует Dep.target, вызовет проблемы с производительностью, поэтому необходимо выяснить, где эти коды записываются для выполнения.Другими словами, чтобы выяснить, где неправильное использование этого для чтения данных в данных может вызвать проблемы с производительностью.
Во втором разделе вводится, что Dep.target будет выполняться после назначенияvalue = this.getter.call(vm, vm)
,вthis.getter
Это функция, поэтому, если вы используете ее для чтения данных, она будет собирать зависимости, и если ею злоупотреблять, это вызовет проблемы с производительностью.
this.getter
присваивается при создании зависимостей, и каждая зависимостьthis.getter
не то же самое. Давайте представим их один за другим.
-
смотреть (слушатель) зависимый
this.getter
даparsePath
Функция, параметр функции которой является объектом для прослушивания.var bailRE = new RegExp(("[^" + (unicodeRegExp.source) + ".$_\\d]")); function parsePath(path) { if (bailRE.test(path)) { return } var segments = path.split('.'); return function(obj) { for (var i = 0; i < segments.length; i++) { if (!obj) { return } obj = obj[segments[i]]; } return obj } }
в коде, показанном ниже
a
иa.b.c
Передать как параметрparsePath
Функция возвращает функцию, присвоеннуюthis.getter
,воплощать в жизньthis.getter.call(vm, vm)
получитеthis.a
иthis.a.b.c
значение .В этом процессе не будет сцены злоупотребления этим для чтения данных в данных.watch:{ a:function(newVal, oldVal){ //做点什么 } } vm.$watch('a.b.c', function (newVal, oldVal) { // 做点什么 })
-
вычисляемый (вычисляемое свойство) зависимый
this.getter
Их два, если значение вычисляемого свойства является функцией, тоthis.getter
это функция. Если значение вычисляемого свойства является объектом, тоthis.getter
Это значение атрибута получения этого объекта, а значение атрибута получения также является функцией. В этой функции могут быть сценарии, в которых эта функция используется для чтения данных в данных.Например, код выглядит следующим образом.computed:{ d:function(){ let result = 0; for(let key in this.a){ if(this.a[key].num > 20){ result += this.a[key].num + this.b + this.c; }else{ result += this.a[key].num + this.e + this.f; } } return result; } }
в вычисляемом свойстве
d
Существует злоупотребление этим для чтения данных данных. вthis.a
представляет собой массив, в настоящее время значение Dep.target является вычисляемым свойствомd
Эта зависимость в циклеthis.a
используйте это, чтобы получитьa
,b
,c
,e
,f
данные, которые подвергаются ряду сложных логических операций для повторного сбора вычисляемых свойствd
эта зависимость. приводит к получению вычисляемого свойстваd
Значение , замедляет работу, создавая проблемы с производительностью. -
Наблюдатель за рендерингом
this.getter
это такая функция:
updateComponent = function() {
vm._update(vm._render(), hydrating);
};
вvm._render()
Функция рендеринга, созданная шаблоном шаблона, будет преобразована в виртуальный DOM (VNode):vnode = render.call(vm._renderProxy, vm.$createElement);
, приведите пример, иллюстрирующий, что такое функция рендеринга render.
Например шаблон шаблона:
<template>
<div class="wrap">
<p>{{a}}<span>{{b}}</span></p>
</div>
</template>
Функция рендеринга рендеринга генерируется через vue-loader следующим образом:
(function anonymous() {
with(this) {
return _c('div', {
attrs: {
"class": "wrap"
}
}, [_c('p', [_v(_s(a)), _c('span', [_v(_s(b))])])])
}
})
вwith
Целью оператора является указание объекта по умолчанию для оператора или группы операторов, например.with(this){ a + b }
эквивалентthis.a + this.b
, затем используйте его в шаблоне шаблона{{ a }}
Скорее используйте это для чтения данных вa
данные. Следовательно, в рендере функции рендеринга, сгенерированном шаблоном шаблона, также может быть сцена злоупотребления этим для чтения данных в данных. Например, код выглядит так:
<template>
<div class="wrap">
<div v-for=item in list>
<div> {{ arr[item.index]['name'] }} </div>
<div> {{ obj[item.id]['age'] }} </div>
</div>
</div>
</template>
которые используютv-for
циклlist
В процессе массива постоянно используйте это для чтения данныхarr
,obj
Данные, заставляющие эти данные выполнять ряд сложных логических операций для повторного сбора этой зависимости, что приводит к более медленному начальному рендерингу, что приводит к проблемам с производительностью.
4. Как не злоупотреблять этим для чтения данных в данных
Таким образом, неправильное использование этого для чтения данных в данных в вычисляемых свойствах и шаблонах шаблонов приведет к повторному сбору зависимостей, что приведет к проблемам с производительностью.Как избежать этой ситуации.
- Как избежать вычисляемых свойств
Используйте назначение деструктурирования объекта ES6, чтобы избежать, значение вычисляемого свойства является функцией, параметр которой является экземпляром Vuethis
Object, приведенный выше пример неправильного использования this в вычисляемых свойствах можно оптимизировать следующим образом.
До оптимизации:
computed:{
d:function(){
let result = 0;
for(let key in this.a){
if(this.a[key].num > 20){
result += this.a[key].num + this.b + this.c;
}else{
result += this.a[key].num + this.e + this.f;
}
}
return result;
}
}
Оптимизировано:
computed: {
d({ a, b, c, e, f }) {
let result = 0;
for (let key in a) {
if (a[key].num > 20) {
result += a[key].num + b + c;
} else {
result += a[key].num + e + f;
}
}
return result;
}
}
Вышеприведенное использует назначение деструктурирования для продвижения данных в данных.a
,b
,c
,e
,f
присвоить соответствующей переменнойa
,b
,c
,e
,f
, а затем данные данных могут быть доступны через эти переменные в вычисляемом свойстве без запуска зависимой коллекции соответствующих данных в данных. Таким образом, данные в data считываются только один раз, и запускается только одна коллекция зависимостей, что позволяет избежать проблем с производительностью, вызванных повторяющимися коллекциями зависимостей.
- Как избежать шаблона шаблона
обработка досрочноv-for
Данные, используемые в цикле, а не вv-for
Прочитайте данные массива и типа объекта в цикле. Приведенный выше пример злоупотребления этим в шаблоне шаблона можно оптимизировать следующим образом.
Предположениеlist
,arr
,obj
все данные, возвращаемые сервером, иarr
иobj
Он не используется ни в одном модульном рендеринге и может быть оптимизирован таким образом.
До оптимизации:
<template>
<div class="wrap">
<div v-for=item in list>
<div> {{ arr[item.index]['name'] }} </div>
<div> {{ obj[item.id]['age'] }} </div>
</div>
</div>
</template>
Оптимизировано:
<template>
<div class="wrap">
<div v-for=item in listData>
<div{{item.name}} </div>
<div>{{item.age}}</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
list: [],
}
},
created(){
// 在这里定义arr和obj避免被转成响应式
this.arr = [];
this.obj = {};
},
computed: {
listData: function ({list}) {
list.forEach(item => {
item.name = this.arr[item.index].name;
item.age = this.obj[item.id].age;
})
return list;
}
},
}
</script>