[Vue Principle] Diff — процесс сравнения в исходной версии

Vue.js
[Vue Principle] Diff — процесс сравнения в исходной версии

Статью написать не просто, поставь лайк, брат

Сосредоточьтесь на обмене исходным кодом Vue, статья разделена на общеупотребительную и исходную версии, общеупотребительная версия помогает понять принцип работы, исходная версия помогает понять внутренние детали, давайте учиться вместе Исследование на основе версии Vue【2.5.17】

Если вы находите типографику уродливой, пожалуйста, нажмитессылка нижеили потяните внизОбратите внимание на публичный аккаунттоже хорошо

[Vue Principle] Diff — процесс сравнения в исходной версии

Сегодня я, наконец, начал исследовать ключевой момент Vue, обновляющий DOM, а именно Diff.

Контента Diff не так уж и много, но если вы хотите рассказать о нем подробно, вам придется много говорить, и вам нужно сопоставить много картинок.

Это последняя статья Диффа, самая важная и самая подробная.

Поэтому в этой статье много контента, поэтому начнем с обзора контента.

1、分析 Diff 源码比较步骤

2、个人思考为什么如此比较

3、写个例子,一步步走个Diff 流程

Статья очень длинная и очень подробная.Если вас интересует этот контент, рекомендуется также читать исходный код во время чтения.Если вы пока не понимаете этот контент, вы можете прочитать народную версию, которая делает не включать исходный код в первую очередь.Diff - Народная версия

Начнем наш текст

公众号

в предыдущем постеDiff - Исходная версия diff от нового экземпляра для запуска, мы изучили, как работает Vue, от создания экземпляра до запуска сравнения

У вас все равно должно сложиться впечатление, что важной функцией, участвующей в Diff, является createPatchFunciton.

var patch = createPatchFunction();

Vue.prototype.__patch__ =  patch

Итак, давайте посмотрим на эту функцию


createPatchFunction

function createPatchFunction() {  

    return function patch(

        oldVnode, vnode, parentElm, refElm    

    ) {      

        // 没有旧节点,直接生成新节点

        if (!oldVnode) {
            createElm(vnode, parentElm, refElm);
        } 
        else {     
            // 且是一样 Vnode

            if (sameVnode(oldVnode, vnode)) {                

                // 比较存在的根节点

                patchVnode(oldVnode, vnode);
            } 
            else {    

                // 替换存在的元素

                var oldElm = oldVnode.elm;                

                var _parentElm = oldElm.parentNode    

                // 创建新节点

                createElm(vnode, _parentElm, oldElm.nextSibling);   

                // 销毁旧节点

                if (_parentElm) {
                    removeVnodes([oldVnode], 0, 0);
                }
            }
        }        

        return vnode.elm

    }
}

Что делает эта функция

Чем отличается новая нода от старой ноды, то полное обновление

Итак, вы видите получение oldVnode и vnode

Процесс обработки делится на

1、没有旧节点

2、旧节点 和 新节点 自身一样(不包括其子节点)

3、旧节点 和 新节点自身不一样

Давайте кратко рассмотрим эти три процесса.

1 нет старого узла

Старого узла нет, а значит страница только инициализирована, на данный момент сравнивать вообще не нужно.

Все новые напрямую, поэтому просто вызовите createElm

2 Старый узел такой же, как и сам новый узел

Судя по одинаковым ли нодам через sameVnode эта функция упоминалась в предыдущей статье

Когда старый узел и новый узел совпадают, вызовите patchVnode напрямую для обработки этих двух узлов.

patchVnode расскажет об этой функции ниже

Прежде чем говорить о patchVnode, давайте подумаем, что делает эта функция?

Что нам нужно делать, когда два Vnode сами по себе одинаковы?

Прежде всего, так же, как и он сам, мы можем просто понять, что два атрибута Vnode такие же, как тег и ключ

Затем мы не знаем, совпадают ли его дочерние узлы, поэтому нам определенно нужно сравнить дочерние узлы.

Поэтому одной из функций patchVnode является сравнение дочерних узлов

3 Старый узел и новый узел сами по себе не совпадают

Когда два узла не совпадают, это нетрудно понять, создайте новый узел напрямую, удалите старый узел


patchVnode

В предыдущей функции createPatchFunction есть функция patchVnode

Мы подумали, что одной из функций этой функции является сравнение потомков двух Vnodes.

Это то, что мы думаем, мы можем сначала перейти к исходному коду

function patchVnode(oldVnode, vnode) { 

    if (oldVnode === vnode) return

    var elm = vnode.elm = oldVnode.elm;    

    var oldCh = oldVnode.children;    

    var ch = vnode.children;   

    // 更新children

    if (!vnode.text) {   

        // 存在 oldCh 和 ch 时

        if (oldCh && ch) {            

            if (oldCh !== ch) 

                updateChildren(elm, oldCh, ch);

        }    

        // 存在 newCh 时,oldCh 只能是不存在,如果存在,就跳到上面的条件了

        else if (ch) {   

            if (oldVnode.text) elm.textContent = '';      

            for (var i = 0; i <= ch.length - 1; ++i) {

                createElm(
                  ch[i],elm, null
                );
            }

        } 

        else if (oldCh) {     

            for (var i = 0; i<= oldCh.length - 1; ++i) {
            
                oldCh[i].parentNode.removeChild(el);
            }

        } 

        else if (oldVnode.text) {
            elm.textContent = '';
        }
    } 

    else if (oldVnode.text !== vnode.text) {
        elm.textContent = vnode.text;
    }
}

Давайте проанализируем эту функцию сейчас

Да, как мы и думали, эта функция сравнивает и обрабатывает дочерние узлы.

В общем, что делает эта функция

1. Если Vnode является текстовым узлом, обновите текст (текстовый узел не имеет дочерних узлов)

2. Если у Vnode есть дочерние узлы, сравните и обновите дочерние узлы.

Еще одно резюме состоит в том, что эта функция в основном выполняет два вида обработки суждений.

1. Является ли Vnode текстовым узлом

2. Есть ли у Vnode дочерние узлы?

Давайте взглянем на подробный анализ этих шагов

1 Vnode — это текстовый узел

Когда VNode имеет текстовый атрибут, это доказывает, что Vnode является текстовым узлом.

Сначала мы можем взглянуть на то, как выглядит Vnode текстового типа.

公众号

Поэтому, когда Vnode является текстовым узлом, все, что вам нужно сделать, это обновить текст.

Есть также две процедуры

1. Когда новый VNode.text существует и отличается от старого VNode.text

Напрямую обновить текстовое содержимое этого DOM

elm.textContent = vnode.text;

Примечание: textContent — это атрибут реального DOM, который сохраняет текст DOM, поэтому обновляйте этот атрибут напрямую.

2. Текст нового Vnode пуст, напрямую назначьте текст DOM пустому

elm.textContent = '';

2 Vnode имеет дочерние узлы

Когда у Vnode есть дочерние узлы, его необходимо сравнить, чтобы завершить обновление, потому что он не знает, совпадают ли дочерние узлы старого и нового узлов.

Есть три процедуры

1. И у старых, и у новых узлов есть дочерние узлы, и они не совпадают

2. Только новые узлы

3. Только старые узлы

Последние два узла, я думаю, разберутся все, но давайте поговорим об этом

1 только новые узлы

Есть только новые узлы, старых узлов нет, поэтому сравнения нет, все узлы совершенно новые

Так что просто создавайте все новые.Новый относится к созданию всех новых DOM и добавлению их к родительскому узлу.

2 только старые узлы

Есть только старые узлы и нет новых узлов, что указывает на то, что обновленная страница, все старые узлы исчезли

Тогда все, что вам нужно сделать, это удалить все старые узлы.

То есть удалить DOM напрямую

3 И старые, и новые узлы имеют дочерние узлы, и они не совпадают

Эй, есть новая функция, updateChildren

Предупреждение, эта функция очень важна.Это основной модуль Diff и содержит идею Diff.

Это может немного сбивать с толку, но не бойтесь, я верю, что благодаря своим исследованиям я смогу немного понять

Точно так же давайте подумаем о роли updateChildren

Помните условия, когда существуют и новый узел, и старый узел, как их сравнить, чтобы узнать, в чем разница?

О да, используя обход, сравните новый дочерний узел со старым дочерним узлом один за другим

Если то же самое, не обновляйте, если нет, обновляйте

Давайте проверим наши идеи и изучим исходный код updateChildren.


updateChildren

Эта функция очень длинная, но это не сложно. Он разделен на несколько процедур обработки, но это может быть немного запутанным.

Или вы можете сначала пропустить исходный код и посмотреть анализ, или просто посмотреть анализ и посмотреть исходный код.

function updateChildren(parentElm, oldCh, newCh) {

    var oldStartIdx = 0;    

    var oldEndIdx = oldCh.length - 1;    

    var oldStartVnode = oldCh[0];    

    var oldEndVnode = oldCh[oldEndIdx];    

    var newStartIdx = 0;    

    var newEndIdx = newCh.length - 1;    

    var newStartVnode = newCh[0];    

    var newEndVnode = newCh[newEndIdx];    

    var oldKeyToIdx, idxInOld, vnodeToMove, refElm;



    // 不断地更新 OldIndex 和 OldVnode ,newIndex 和 newVnode

    while (

        oldStartIdx <= oldEndIdx && 

        newStartIdx <= newEndIdx

    ) {        

        if (!oldStartVnode) {

            oldStartVnode = oldCh[++oldStartIdx];
        }     

        else if (!oldEndVnode) {

            oldEndVnode = oldCh[--oldEndIdx];
        }   

        //  旧头 和新头 比较
        else if (sameVnode(oldStartVnode, newStartVnode)) {

            patchVnode(oldStartVnode, newStartVnode);

            oldStartVnode = oldCh[++oldStartIdx];
            newStartVnode = newCh[++newStartIdx];
        }    

        //  旧尾 和新尾 比较

        else if (sameVnode(oldEndVnode, newEndVnode)) {

            patchVnode(oldEndVnode, newEndVnode);

            oldEndVnode = oldCh[--oldEndIdx];
            newEndVnode = newCh[--newEndIdx];
        }                
               

        // 旧头 和 新尾 比较

        else if (sameVnode(oldStartVnode, newEndVnode)) {

            patchVnode(oldStartVnode, newEndVnode);            

            // oldStartVnode 放到 oldEndVnode 后面,还要找到 oldEndValue 后面的节点

            parentElm.insertBefore(

                oldStartVnode.elm, 

                oldEndVnode.elm.nextSibling

            );
            
            oldStartVnode = oldCh[++oldStartIdx];
            newEndVnode = newCh[--newEndIdx];
        }   

        //  旧尾 和新头 比较

        else if (sameVnode(oldEndVnode, newStartVnode)) {

            patchVnode(oldEndVnode, newStartVnode);            


            // oldEndVnode 放到 oldStartVnode 前面

            parentElm.insertBefore(oldEndVnode.elm, oldStartVnode.elm);

            oldEndVnode = oldCh[--oldEndIdx];
            newStartVnode = newCh[++newStartIdx];
        }        


        // 单个新子节点 在 旧子节点数组中 查找位置

        else {    

            // oldKeyToIdx 是一个 把 Vnode 的 key 和 index 转换的 map

            if (!oldKeyToIdx) {
                oldKeyToIdx = createKeyToOldIdx(

                    oldCh, oldStartIdx, oldEndIdx

                );

            }     

            // 使用 newStartVnode 去 OldMap 中寻找 相同节点,默认key存在

            idxInOld = oldKeyToIdx[newStartVnode.key]        

            //  新孩子中,存在一个新节点,老节点中没有,需要新建 

            if (!idxInOld) {  

                //  把  newStartVnode 插入 oldStartVnode 的前面

                createElm(

                    newStartVnode, 

                    parentElm, 

                    oldStartVnode.elm

                );

            }            

            else {                

                //  找到 oldCh 中 和 newStartVnode 一样的节点

                vnodeToMove = oldCh[idxInOld];     
                if (sameVnode(vnodeToMove, newStartVnode)) {

                    patchVnode(vnodeToMove, newStartVnode);  
                
                    // 删除这个 index

                    oldCh[idxInOld] = undefined;                    
                    // 把 vnodeToMove 移动到  oldStartVnode 前面

                    parentElm.insertBefore(

                        vnodeToMove.elm, 

                        oldStartVnode.elm

                    );

                }                

                // 只能创建一个新节点插入到 parentElm 的子节点中

                else {                    

                    // same key but different element. treat as new element

                    createElm(

                        newStartVnode, 

                        parentElm, 

                        oldStartVnode.elm

                    );

                }
            }            

            // 这个新子节点更新完毕,更新 newStartIdx,开始比较下一个

            newStartVnode = newCh[++newStartIdx];
        }
    }    



    // 处理剩下的节点

    if (oldStartIdx > oldEndIdx) {  

        var newEnd = newCh[newEndIdx + 1]

        refElm = newEnd ? newEnd.elm :null;        
        for (; newStartIdx <= newEndIdx; ++newStartIdx) {

            createElm(
               newCh[newStartIdx], parentElm, refElm
            );
        }
    }    

    // 说明新节点比对完了,老节点可能还有,需要删除剩余的老节点

    else if (newStartIdx > newEndIdx) {       

        for (; oldStartIdx<=oldEndIdx; ++oldStartIdx) {

            oldCh[oldStartIdx].parentNode.removeChild(el);
        }
    }
}

В первую очередь необходимо уточнить, чем занимается эта функция

Новый дочерний узел и старый дочерний узел обрабатываются, и цикл проходит и сравнивает их один за другим.

Как прокрутить?

1. Используйте пока

2. И новый, и старый массивы узлов настроены с двумя индексами в начале и в конце.

Два индекса нового узла: newStartIdx, newEndIdx

Два индекса старых узлов: oldStartIdx, oldEndIdx

Траверс в виде двух сторон, окруженных серединой

После завершения сравнения дочерних узлов головы startIdx увеличивается на 1.

После завершения сравнения дочерних узлов в хвосте endIdex уменьшается на 1.

Пока пройден один из массивов (startIdx

公众号

Процесс обработки исходного кода разделен на две части.

1. Сравните старые и новые дочерние узлы

2. После сравнения обработайте оставшиеся узлы

Давайте объясним эти два процесса один за другим

1 Сравните старые и новые дочерние узлы

Примечание. Здесь есть два массива, один из которых представляет собой новый массив sub-Vnode, а другой — старый массив sub-Vnode.

Во время сравнения в два массива не будет внесено никаких изменений (например, без вставки или удаления их дочерних элементов).

И весь процесс сравнения напрямую вставляет и удаляет реальную страницу DOM.

Давайте проясним, какова цель сравнения?

Найдите один и тот же дочерний узел в старом и новом дочерних узлах, попробуйте использовать перемещение вместо нового для обновления DOM.

Будут созданы только новые, если они действительно отличаются.

Сравните шаги плана обновления

Сначала подумайте, не перемещайте DOM

Во-вторых, рассмотрите возможность перемещения DOM

Окончательное рассмотрение, новый/удаленный DOM

Не могу двигаться, постарайся не двигаться. Если он не работает, переместите его, если он не работает, то создайте новый.

Начнем с логики сравнения в исходном коде.

Пять логик сравнения следующие:

1、旧头 == 新头

2、旧尾 == 新尾

3、旧头 == 新尾

4、旧尾 == 新头

5、单个查找

Давайте проанализируем эти пять логик сравнения

1 старая голова == новая голова

sameVnode(oldStartVnode, newStartVnode)

Когда две старые и новые головки одинаковые, ничего делать не нужно.

В соответствии с нашим первым шагом обновление завершается без перемещения DOM.

Но см. предложение, patchVnode

Просто для продолжения обработки дочерних узлов этих двух одинаковых узлов или для обновления текста

Поскольку мы не рассматриваем многоуровневую структуру DOM, если новый и старый заголовки совпадают, это конец.

Можно сразу перейти к следующему циклу

newStartIdx ++ , oldStartIdx ++

公众号

2 старый хвост == новый хвост

sameVnode(oldEndVnode, newEndVnode)

Та же обработка, что и при прямом контакте

Хвост и хвост одинаковые, переходим сразу к следующей петле

newEndIdx ++ , oldEndIdx ++

公众号

3 старая голова == новый хвост

sameVnode(oldStartVnode, newEndVnode)

Этот шаг не соответствует отказу от перемещения DOM, поэтому вы можете перемещать только DOM

Как двигаться?

Исходный код такой

parentElm.insertBefore(
    oldStartVnode.elm, 
    oldEndVnode.elm.nextSibling
);

Перемещаясь по положению нового дочернего узла, старая головка находится в конце нового дочернего узла.

Так что поместите дом oldStartVnode за oldEndVnode

Но поскольку нет возможности поставить дом позади, можно использовать только insertBefore.

То есть ставится перед узлом после oldEndVnode

Схема вот такая

公众号

затем обновите оба индекса

oldStartIdx++,newEndIdx--

4 старый хвост == новая голова

sameVnode(oldEndVnode, newStartVnode)

То же самое не соответствует не перемещать DOM, вы можете только перемещать DOM

Как двигаться?
parentElm.insertBefore(
    oldEndVnode.elm, 
    oldStartVnode.elm
);

Поместите DOM oldEndVnode непосредственно перед текущим oldStartVnode.elm.

Схема вот такая

公众号

затем обновите оба индекса

oldEndIdx--,newStartIdx++

5 Поиск одного обхода

Когда ни одна из предыдущих четырех логик сравнения не работает, это последний способ справиться с этим.

Возьмите дочерний элемент нового дочернего узла, пройдите напрямую по массиву старых дочерних узлов и найдите тот же самый узел.

Процесс, вероятно,

1. Создайте таблицу сопоставления со старым массивом дочерних узлов с vnode.key в качестве ключа.

2. Получите дочерний элемент в новом массиве дочерних узлов и оцените, находится ли его ключ на приведенной выше карте.

3. Если он не существует, создайте новый DOM

4. Существовать, продолжать ли судить о том же Vnode

Поговорим об этом подробнее ниже

1 Создайте таблицу карт

Функция этой таблицы сопоставления в основном состоит в том, чтобы определить, какие старые дочерние узлы существуют.

Например, ваш старый массив дочерних узлов

[{    
    tag:"div",  key:1
},{  

    tag:"strong", key:2
},{  

    tag:"span",  key:4
}]

Создайте таблицу сопоставления oldKeyToIdx с помощью createKeyToOldIdx

{vnodeKey: индекс массива}

Имя свойства — vnode.key, а значение свойства — позиция vnode в дочерних элементах.

Вот и все (конкретный исходный код см. в предыдущей статье Diff - связанные вспомогательные функции версии исходного кода)

oldKeyToIdx = {
    1:0,
    2:1,
    4:2
}
2 Определите, существует ли новый дочерний узел в массиве старых дочерних узлов.

Получите дочерний Vnode в новом дочернем узле, а затем получите его ключ

Чтобы сопоставить таблицу сопоставления, чтобы определить, есть ли одинаковые узлы

oldKeyToIdx[newStartVnode.key]
3 не существует в старом массиве дочерних узлов

Создайте DOM напрямую и вставьте его перед oldStartVnode

createElm(newStartVnode, parentElm, oldStartVnode.elm);

公众号

4 существует в старом массиве дочерних узлов

Найдите старый дочерний узел, а затем оцените, является ли он тем же Vnode, что и новый дочерний узел.

Если то же самое, перейдите прямо к началу oldStartVnode.

Если отличается, создайте и вставьте непосредственно перед oldStartVnode

Выше мы говорили, что процесс сравнения дочерних узлов делится на два

1. Сравните старые и новые дочерние узлы

2. После сравнения обработайте оставшиеся узлы

Сравнение старого и нового подузлов было сказано выше, и теперь идет другой процесс для сравнения оставшихся узлов, подробности см. Ниже.

Обработать возможные оставшиеся узлы

В updateChildren после сравнения старого и нового массивов в массиве могут остаться какие-то узлы, которые не были обработаны, поэтому здесь требуется унифицированная обработка.

1 Новый дочерний узел пройден
newStartIdx > newEndIdx

Новый дочерний узел пройден, а старый дочерний узел все еще может быть оставлен.

Поэтому нам нужно пакетно удалить старые узлы, которые могут быть оставлены!

Это обход оставшихся узлов и удаление DOM один за другим.

for (; oldStartIdx <= oldEndIdx; ++oldStartIdx) {
    oldCh[oldStartIdx]

    .parentNode

    .removeChild(el);
}

公众号

2 Старый дочерний узел пройден
oldStartIdx > oldEndIdx

Старый дочерний узел был пройден, и у нового дочернего узла могут быть остатки

Итак, нам нужно разобраться с оставшимися новыми дочерними узлами.

Очевидно, что оставшиеся новые дочерние узлы не существуют в старых дочерних узлах, поэтому создаются все новые.

for (; newStartIdx <= newEndIdx; ++newStartIdx) {
   createElm(
      newCh[newStartIdx], 

      parentElm, 

      refElm

   );
}

А вот у нового проблема, то есть куда его вставлять?

Так что refElm в нем стал подозрительным, посмотрите исходники

var newEnd = newCh[newEndIdx + 1]

refElm = newEnd ? newEnd.elm :null;

refElm получает узел после newEndIdx

Узел, который в данный момент не обрабатывается, называется newEndIdx.

То есть, если узел newEndIdx+1 существует, он должен быть обработан.

Если newEndIdx не был перемещен и всегда является последним битом, то newCh[newEndIdx + 1] не существует.

Тогда refElm пуст, тогда все оставшиеся новые узлы добавляются в конец дочернего элемента родительского узла, что эквивалентно

for (; newStartIdx <= newEndIdx; ++newStartIdx) {     
    parentElm.appendChild(

        newCh[newStartIdx]

    );

}

Если newEndIdx был перемещен, он добавляется один за другим перед refElm, что эквивалентно

for (; newStartIdx <= newEndIdx; ++newStartIdx) {
    parentElm.insertBefore(

        newCh[newStartIdx] ,

        refElm 

    );

}

Как показано

公众号


Подумайте, почему сравнение

Мы закончили весь контент Diff, и каждый должен понять идею Diff.

Но я заставил себя задуматься над вопросом, который

Зачем так сравнивать?

Ниже приведены сугубо личные непристойные мысли, без официальной сертификации, только для справки.

Все наши сравнения заключаются в том, чтобы найти те же дочерние узлы, что и новый дочерний узел, и старый дочерний узел.

И целью нашей сравнительной обработки является

1, не могу двигаться, постарайся не двигаться

2. Нет другого выбора, кроме как переехать

3. Не работает, создавай или удаляй

Прежде всего, в начале сравнения это должно быть в соответствии с нашей первой целью не двигаться, чтобы найти узлы, которые нельзя перемещать.

А голова, хвост и хвост больше соответствуют нашей первой цели, так она появилась в начале, хм, в этом можно разобраться

Затем мы переходим к нашей второй цели, согласно подходу updateChildren, есть

Сравнение старой головы и новой головы, сравнение старой головы и новой головы, сравнение с одним поиском

Я начинаю задаваться вопросом, а? Я знаю, что сравнения «голова к хвосту» предназначены для движения, но почему это сравнение происходит?

Очевидно, я могу использовать один метод поиска для выполнения всех операций перемещения?

Я долго думал о связи между головой и хвостом, и думал, что это может быть, чтобы избежать потребления в экстремальных ситуациях? ?

Как сказать?

Например, когда мы удаляем сравнение головы и хвоста, все используют один метод поиска.

Если головной и хвостовой узлы совпадают, необходимо пройти узел, чтобы найти конец, чтобы найти тот же узел.

Это слишком дорого, поэтому здесь добавлено прямое сравнение, чтобы исключить операции потребления, вызванные экстремальными ситуациями.

Конечно, это только моя личная идея, только для справки, хотя при этом я сделал пример теста.

В дочерний узел добавляется подэлемент b div с двумя прямыми сравнениями.

oldCh = ['header','span','div','b']
newCh = ['sub','b','div','strong']

Используйте Vue для обновления, сравните скорость обновления, затем обновите десять раз, рассчитайте среднее

1. Все используют один поиск, время 0,91 мс

2. Добавьте сравнение головы и хвоста, время 0,853 мс.

Это действительно быстрее


идти процесс

Я считаю, что после такой длинной статьи все еще не собрали в уме все пункты знаний, и могут быть еще немного расплывчаты в отношении всего процесса

Все в порядке, давайте сейчас возьмем пример, шаг за шагом пройдем процесс и завершим обновление.

Следующие узлы, зеленый означает необработанные, серый означает обработанный, светло-зеленый означает обрабатываемый, красный означает недавно вставленный, следующим образом

公众号

Теперь необходимо обновить Vue.Есть следующие две группы новых и старых дочерних узлов, которые необходимо сравнить, чтобы определить, какие узлы необходимо обновить.

公众号

1 прямое сравнение, узлы одинаковые, перемещать не нужно, просто обновите индекс

公众号

индекс обновления, newStartIdx++, oldStartIdx++

Начать следующий раунд обработки

После ряда суждений [Old Head 2] и [New End 2] совпадают и перемещаются непосредственно в конец oldEndVnode.

公众号

обновить индекс, newEndIdx--, oldStartIdx++

Начать следующий раунд обработки

3 После серии суждений [Old Head 2] и [New Tail 2] совпадают и перемещаются прямо к началу oldStartVnode.

公众号

Индекс обновления, OldendidX-, NewstartIdx ++

Начать следующий раунд сравнения

4 Остался только один узел, иди на Страшный суд, одиночный поиск

Не могу найти то же самое, напрямую создайте и вставьте его перед oldStartVnode

公众号

индекс обновления, newStartIdx++

В этот момент newStartIdx> newEndIdx завершает цикл

5 Пакетное удаление старых узлов, которые могут остаться

На данный момент в старом массиве Vnode и oldStartIdx, и oldEndIdx указывают на один и тот же узел, поэтому просто удалите узел oldVnode-4.

ОК, относительно завершил все процессы

Да, Diff-контент закончился, спасибо за просмотр

公众号


наконец

Ввиду моих ограниченных возможностей неизбежно будут упущения и ошибки.Пожалуйста, потерпите меня.Если есть какие-либо неуместные описания, пожалуйста, свяжитесь со мной в фоновом режиме, большое спасибо.

公众号