Как работает ng-repeat?

Я анализировал ng-repeat и извлекал прикрепленные блоки кода, видя, что они составляют логику, которая обрабатываетповторяющий алгоритм (который я хочу понять, как это работает).

У меня довольно много вопросов, но, поскольку они все о внутренностях ng-repeat, я решил задать их всем здесь. Я не вижу смысла разделять их на разные вопросы. Я отметил, на какую строку (и) кода относится каждый вопрос.

Почему они должны убедиться, чтоtrackById не роднойhasOwnProperty функционировать? (вот что этоassertNotHasOwnProperty функция делает, часть внутреннего API Angular)Что касается моей интуиции, этот код выполняется на элементах, уже находящихся в повторителе, когда он должен обновить коллекцию - он просто берет их и помещает в список для обработки, верно?Этот блок кода явно ищет дубликаты в коллекции репитеров. Но как именно это сделать, это вне меня. Пожалуйста, объясни.Почему Angular должен хранить объект блока какnextBlockMap а также вnextBlockOrder?Чтоblock.endNode а такжеblock.startNode?Я предполагаю, что ответ на вышеуказанный вопрос прояснит, как работает этот алгоритм, но, пожалуйста, объясните, почему он должен проверять,nextNode был)'$$NG_REMOVED'?Что здесь происходит? Опять же, я предполагаю, что вопрос 6 уже даст ответ на этот вопрос. Но все же указывая на это.

Как я уже сказал, я просмотрел ng-repeat, чтобы найти код, который я считаю относящимся к повторяющемуся механизму. Кроме того, я понимаю остальную часть директивы. Итак, без лишних слов, вот код (из v1.2.0):

      length = nextBlockOrder.length = collectionKeys.length;
      for (index = 0; index < length; index++) {
       key = (collection === collectionKeys) ? index : collectionKeys[index];
       value = collection[key];
       trackById = trackByIdFn(key, value, index);

       // question #1
       assertNotHasOwnProperty(trackById, '`track by` id');

       // question #2
       if (lastBlockMap.hasOwnProperty(trackById)) {
         block = lastBlockMap[trackById];
         delete lastBlockMap[trackById];
         nextBlockMap[trackById] = block;
         nextBlockOrder[index] = block;

       // question #3
       } else if (nextBlockMap.hasOwnProperty(trackById)) {
         // restore lastBlockMap
         forEach(nextBlockOrder, function(block) {
           if (block && block.startNode) lastBlockMap[block.id] = block;
         });
         // This is a duplicate and we need to throw an error
         throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
                                                                                                                                                expression,       trackById);

       // question #4
       } else {
         // new never before seen block
         nextBlockOrder[index] = { id: trackById };
         nextBlockMap[trackById] = false;
       }
     }


      for (index = 0, length = collectionKeys.length; index < length; index++) {
        key = (collection === collectionKeys) ? index : collectionKeys[index];
        value = collection[key];
        block = nextBlockOrder[index];


        // question #5
        if (nextBlockOrder[index - 1]) previousNode = nextBlockOrder[index - 1].endNode;

        if (block.startNode) {
          // if we have already seen this object, then we need to reuse the
          // associated scope/element
          childScope = block.scope;

          // question #6
          nextNode = previousNode;
          do {
            nextNode = nextNode.nextSibling;
          } while(nextNode && nextNode[NG_REMOVED]);
          if (block.startNode != nextNode) {
            // existing item which got moved
            $animate.move(getBlockElements(block), null, jqLite(previousNode));
          }
          previousNode = block.endNode;

        } else {
          // new item which we don't know about
          childScope = $scope.$new();
        }

        // question #7
        if (!block.startNode) {
          linker(childScope, function(clone) {
            clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
            $animate.enter(clone, null, jqLite(previousNode));
            previousNode = clone;
            block.scope = childScope;
            block.startNode = previousNode && previousNode.endNode ? previousNode.endNode : clone[0];
            block.endNode = clone[clone.length - 1];
            nextBlockMap[block.id] = block;
          });
        }
      }
      lastBlockMap = nextBlockMap;

Ответы на вопрос(1)

Ваш ответ на вопрос