Петли являются одним из наиболее важных механизмов во всех языках программирования, а петли не открыты практически в любой компьютерной программе с практическим значением (сортировка, запросы и т. Д.). Цикл также является очень хлопотной частью оптимизации программы. Нам часто нужно постоянно оптимизировать сложность программы, но мы запутались в выборе между сложностью времени и сложностью пространства из -за цикла.
В JavaScript есть 3 нативных петли, для () {}, while () {} и do {} while (), а наиболее часто используемые предназначены для () {}.
Тем не менее, для наиболее вероятного цикла, которую игнорируют инженеры JavaScript при оптимизации программ.
Давайте сначала рассмотрим базовые знания для.
Для синтаксиса JavaScript унаследован от языка C, и существует два способа использования основного синтаксиса для петель.
1. Цикл массив
Основной синтаксис для петли
Кода -копия выглядит следующим образом:
для ( / * инициализация * /2 / * Условие суждения * /2 / * обработка цикла * /) {
// ... логический код
}
Мы подробно объясним с помощью кода экземпляра.
Кода -копия выглядит следующим образом:
var array = [1, 2, 3, 4, 5];
var sum = 0;
for (var i = 0, len = array.length; i <len; ++ i) {
sum += массив [i];
}
console.log ('сумма элементов массива/' %d. ', sum);
// => Сумма элементов массива составляет 15.
В этом коде мы сначала определяем и инициализируем массив, в котором хранится элементы, которые будут накоплены, и переменную формирования суммы. Далее мы начинаем петлю. В коде инициализации этого для цикла мы также определяем и инициализируем две переменные: I (счетчик) и Лен (псевдоним длины массива цикла). Когда я меньше, чем Лен, условие цикла устанавливается и выполняется логический код; После того, как каждый логический код будет выполнен, я буду увеличен на 1.
В логическом коде цикла мы добавляем члены массива текущего цикла к переменной суммы.
Этот цикл представлен блок -схемой следующим образом:
Из этой блок -схемы нетрудно обнаружить, что реальное тело цикла в программе не только содержит наш логический код, но и включает в себя суждение о выполнении и обработку цикла, которые реализуют сам цикл.
Таким образом, наши идеи оптимизации будут ясны, и мы можем оптимизировать из четырех аспектов.
1. Код инициализации перед телом цикла
2. Условия суждения исполнения в теле петли
3. Логический код
4. Обработка кода после логического кода
PS: Существует важная связь между первой точкой и вторым пунктом.
1.1 Оптимизировать код инициализации и условия выполнения
Давайте сначала посмотрим на кусок кода, с которым все очень хорошо знакомы.
Кода -копия выглядит следующим образом:
// неправильный!
для (var i = 02 i <list.length2 ++ i) {
// ... логический код
}
Я считаю, что большинство инженеров, которые пишут JavaScript, все еще используют этот, казалось бы, нормальный метод цикла, но почему я говорю, что это неправильно здесь?
Давайте разберем все в этой цикле и посмотрим:
1. Инициализировать код - этот цикл только определяет и инициализирует переменную счетчика.
2. Условие суждения исполнения - это верно, когда счетчик меньше длины списка.
3. Код обработки - счетчик увеличивается на 1.
Давайте рассмотрим блок -схему выше и выясним, есть ли в ней что -то не так?
В реальном образовании корпуса цикла не только есть наш логический код, но и включает в себя суждение о выполнении и код обработки, который реализует сам цикл. Другими словами, условие суждения i <list.length должен быть выполнен до каждого цикла. В JavaScript требуется запрос при чтении свойств или методов объекта.
Вы, кажется, что -то понимаете, верно? В этом решении есть две операции: 1. Запрос атрибута длины из массива списков; 2. Сравните размеры I и List.Length.
Предполагая, что массив списков содержит n элементов, программа должна выполнить 2N операции в решении исполнения этого цикла.
Если мы изменим код на это:
Кода -копия выглядит следующим образом:
// Хорошо
для (var i = 0, len = list.length; i <len; ++ i) {
// ...
}
В этом улучшенном коде мы добавили определение и инициализировали переменную LEN для хранения значения List.Length в коде инициализации перед выполнением цикла тела (соответствующее содержание о переменных, выражениях, указателях и значениях будет обсуждаться во второй статье). Таким образом, нам не нужно снова запрашивать массив списков в решении исполнения в теле цикла, и операнд - половина первоначального.
На приведенных выше этапах мы улучшили временную сложность алгоритма, и как мы должны это сделать, если хотим продолжать оптимизировать пространственную сложность? Если ваш логический код не ограничен порядок цикла, вы можете попробовать следующий метод оптимизации.
Кода -копия выглядит следующим образом:
for (var i = list.length -1; i> = 0; --I) {
// ...
}
Этот код переходит вперед, инвертируя порядок цикла, начиная с последнего индекса элемента (list.length - 1). Чтобы уменьшить количество переменных, необходимых для цикла до 1, и в решении выполнения, количество запросов переменной уменьшается, а время, проведенное до выполнения инструкции процессора, уменьшается.
1.2 Оптимизация логического кода
В цикле мы получаем текущий элемент массива петли, естественно, чтобы сделать некоторые операции на нем или использовать его, что неизбежно приводит к нескольким вызовам элемента.
Кода -копия выглядит следующим образом:
var array = [
{name: 'Will Wen Gunn', Type: 'hentai'},
{name: 'vill lin', тип: 'moegril'}
];
for (var i = array.length -1; i> = 0; --I) {
console.log ('name: %s', array [i] .name);
console.log ('он/она - (n) %s', массив [i] .type);
console.log ('/r/n');
}
/*=>
Имя: Vill Lin
Он/она (n) moegril
Имя: Уилл Вэнь Ганн
Он/она (n) хентай
*/
В этом коде программа должна запросить атрибуты имени и типа каждого элемента массива. Если у массива есть n -элементы, программа выполнит 4N объектных запросов.
Кода -копия выглядит следующим образом:
1. Массив [я]
2. Массив [i]
3. Массив [я]
4. Массив [i] .type
Я полагаю, что вы, должно быть, думали о решении в настоящее время, то есть назначить значение текущего элемента массива переменной, а затем использовать его в логическом коде.
Кода -копия выглядит следующим образом:
var array = [
{name: 'Will Wen Gunn', Type: 'hentai'},
{name: 'vill lin', тип: 'moegril'}
];
var person = null;
for (var i = array.length -1; i> = 0 && (person = array [i]); -i) {
console.log ('name: %s', person.name);
console.log ('он/она - (n) %s', person.type);
console.log ('/r/n');
}
человек = null;
Это выглядит намного красивее.
Кода -копия выглядит следующим образом:
1. Массив [i] => var person
2. Person.name
3. Person.Type
Это немного похоже на Foreach в EmcaScript5, но разница между ними огромна, поэтому я не объясню это здесь.
PS: Спасибо за исправление. После экспериментов я обнаружил, что если элементы в массиве определяются непосредственно проходными значениями, значение, полученное в цикле, должно быть значением, а не указателем. Таким образом, определяете ли вы выражения или переменные, будут дополнительные запросы на пространство памяти.
1.3 Оптимизировать код обработки
На самом деле, не так много для оптимизации кода обработки в корпусе петли, а счетчик I достаточно, чтобы увеличить 1 сам по себе.
PS: Если у вас есть хорошие предложения или методы, предоставьте их. :)
2. Круговой объект (объект)
В JavaScript, ибо может также пройти свойства и методы объекта. Следует отметить, что для цикла не может пройти через тип обертывания, к которому принадлежит объект, или о свойствах и методах прототипа в конструкторе.
Синтаксис проще, чем зацикливание массивов.
Кода -копия выглядит следующим образом:
for (/* инициализировать*/ var -ключ в объекте) {
// ... логический код
}
Мы часто используем этот метод для работы на объектах.
Кода -копия выглядит следующим образом:
var person = {
«Имя»: «Уилл Вэнь Ганн»,
«Тип»: 'hentai',
'Skill': [«Программирование», «Фотография», «Говоря», «и т. Д.»]
};
для (var -ключ лично) {
value = person [key];
// Если значение массив, преобразовать его в строку
if (экземпляр значения массива) {
value = value.join (',');
}
console.log (' %s: %s', ключ, значение);
}
/*=>
Имя: Уилл Вэнь Ганн
Тип: Хентай
Навык: программирование, фотография, разговор и т. Д.
*/
Если вы использовали MongoDB, вы обязательно будете знакомы с его механизмом запроса. Поскольку механизм запросов MongoDB похож на душу его API, гибкий метод работы Courd завоевал много популярности и развития импульса.
В реализации API Mongo API реализация запроса использует объекты цикла в больших масштабах.
Кода -копия выглядит следующим образом:
var mydb = nano.db ('mydb');
var mycoll = mydb.collection ('mycoll');
var _cursor = mycoll.find ({
Тип: 'Repo',
Язык: 'JavaScript'
});
_курсор
.sort ({
Звезда: 1
})
.toarray (function (err, row) {
if (err)
return console.error (err);
console.log (ряды);
});
Что нам нужно для оптимизации, так это не сама цикл, а оптимизация объектов, которые вам нужно пройти.
Например, класс наноколликции в NanoDB выглядит как массив, который содержит все элементы или объекты, и использует идентификатор элемента в качестве ключа, а затем хранит элементы.
Но это не так. Студенты, которые использовали подчеркивание, должны знать метод _.invert. Это довольно интересный способ отменить ключи и значения передаваемого объекта.
Кода -копия выглядит следующим образом:
var person = {
«Имя»: «Уилл Вэнь Ганн»,
«Тип»: 'hentai'
};
var _Inverted = _.Invert (человек);
console.log (_Inverted);
/*=>
{
'Will Wen Gunn': 'name',
'hentai': 'type'
}
*/
Если вам нужно использовать объект Loop для запроса значений определенных свойств объекта, вы можете попробовать следующий метод.
Кода -копия выглядит следующим образом:
var person = {
«Имя»: «Уилл Вэнь Ганн»,
«Тип»: 'hentai'
};
var name = 'Уилл Вэнь Ганн';
var _Inverted = _.Invert (человек);
if (_Inverted [name] === 'name') {
console.log ('поймал!');
}
// => Поймал!
Тем не менее, существует не так много оптимизации для использования для объектного запроса, и все должно основываться на фактических потребностях. : p
Затем мы посмотрим на две другие петли, while () {} и do {} while (). Я считаю, что любой друг, который получил курс по информатике, будет знаком с этими двумя циклами. Единственная разница между ними - логический порядок выполнения тела петли.
Порядок выполнения while () {} аналогичен порядку () {}. Суждения о выполнении выполняются перед логическим кодом, но код инициализации и обработки опущены.
Когда задается условие, логический код выполняется до тех пор, пока условие больше не удерживается.
Кода -копия выглядит следующим образом:
var sum = 0;
while (sum <10) {
сумма + = сумма + 1;
}
console.log (sum);
// => 15
do {} while () ставит решение о выполнении после логического кода, что означает «сначала мертвы, а затем воспроизводить».
Кода -копия выглядит следующим образом:
var sum = 0;
делать {
сумма + = сумма + 1;
} while (sum <10);
console.log (sum);
// => 15
While () {} и do {} while () также не требует счетчика, но используйте определенные условия, чтобы определить, выполнять или продолжать выполнять логический код.
3. while () {} и do {} while ()
while () {} и do {} while () в основном используется в бизнес -логике, а серия операций непрерывно выполняется для достижения определенной цели, таких как очереди задач.
Но эти две петли опасны, потому что они контролируются только условиями выполнения по умолчанию. Если в логическом коде нет никакого влияния на решение выполнения, произойдет мертвый цикл.
Кода -копия выглядит следующим образом:
var sum = 02
// предупреждение!
while (sum <10) {
sum = 1 + 12
}
Такой код ничем не отличается от (true) {}, поэтому перед использованием необходимо прояснить условия выполнения и как повлиять на условия выполнения.
4. хорошо использовать операторы управления петлями
Я полагаю, что все инженеры JavaScript использовали отчеты о перерыве, но продолжительные операторы относительно редко используются. На самом деле, есть много отличных проектов с открытым исходным кодом JavaScript, которые можно найти.
Чтобы решить функцию оператора продолжения, давайте сначала посмотрим на пример кода
Кода -копия выглядит следующим образом:
// Node.js Broadcast Server
var net = require ('net');
var util = require ('util');
var Broadcastserver = net.createserver ();
// Клиентский магазин
Broadcastserver.clients = [];
// Метод трансляции клиентов
net.socket.prototype.broadcast = function (msg) {
var clients = broadcastserver.clients;
// Получить индекс вещательного клиента в централизованной
var index = client.indexof (this);
for (var i = client.length -1; i> = 0; -i) {
if (i === index) {
// Если это вещательный клиент, текущий корпус петли будет прекращен
продолжать;
}
currclient = клиенты [i];
if (! currclient.destroyed) {
currclient.write (
util.format (
'/r [echo client %s: %d] %s/ninput:',
currclient.remoteaddress, currclient.remoteport, msg)
);
}
}
};
// подключен новый клиент
Broadcastserver.on ('Connection', function (client) {
Froadcastserver.clients.push (клиент);
// Добро пожаловать
client.write ('[вещательный сервер] Welcome!/Ninput:');
client.broadcast (клиент, «присоединился!»);
// Ручка сообщения
client.on ('data', function (msg) {
client.broadcast (msg);
client.write ('/rinput:');
});
// Отключить ручку
client.on ('end', function () {
client.broadcast ('left!');
})
});
// Связывать
Broadcastserver.listen (8080, function () {
console.log ('Broadcast Server.');
});
Этот код реализует вещательный сервер на основе сетевого модуля Node.js. В методе вещания мы используем оператор «Продолжить» для реализации всех подключенных клиентов, которые установили подключения, за исключением вещательного клиента.
Содержание кода довольно простое. Когда клиент должен транслироваться другим клиентам, вызывается метод трансляции соответствующего клиентского объекта для клиента. В методе трансляции программа сначала получит подписание позиции текущего клиента в сборе сокетов кэшированного клиента, а затем пройдет через все розетки клиента. Когда счетчик цикла достигает подписания положения, который он получил ранее, логический код в текущем корпусе цикла будет пропущен, а следующий цикл будет продолжаться.
Я считаю, что инженеры, которые узнали язык C/C ++, получат этот совет из разных мест: «Не используйте заявления о Goto».
Это «печально известное» заявление GOTO на самом деле является контроллером потока кода, и детали оператора GOTO не будут подробно описаны здесь. Тем не менее, в JavaScript нет очевидного заявления о Goto, но из заявлений о перерыве и продолжения заявлений нетрудно найти тень Goto в JavaScript.
Это связано с тем, что операторы перерыва и продолжительные операторы позволяют принимать принятие определенного имени метки для перенаправления кода.
Давайте посмотрим на пример кода, предоставленный MDN.
Кода -копия выглядит следующим образом:
var i, j;
Loop1:
for (i = 0; i <3; i ++) {// Первое утверждение помечено "loop1"
Loop2:
для (j = 0; j <3; j ++) {// Второе для утверждения помечено "loop2"
if (i == 1 && j == 1) {
Продолжить Loop1;
} еще {
console.log ("i =" + i + ", j =" + j);
}
}
}
// Вывод:
// "i = 0, j = 0"
// "i = 0, j = 1"
// "i = 0, j = 2"
// "i = 1, j = 0"
// "i = 2, j = 0"
// "i = 2, j = 1"
// "i = 2, j = 2"
// Обратите внимание, как это пропускает оба "i = 1, j = 1" и "i = 1, j = 2"
В этом примере внедряются двухслойные петли, и за пределами каждого цикла определяется этикетка, которая используется для вызова последующего оператора продолжения.
Первый слой цикла находится в этикетке Loop1, то есть в последующей программе, если метка Loop1 выбран в операторе Contination Orer или Break, самый внешний цикл сломается.
Вторая петля слоя находится в метке Loop2 в петле верхнего уровня. Если метка Loop2 выбран в операторе Contination или Break, она вернется в корпус петли петли верхнего уровня.
Используя операторы управления цикла, мы можем вмешиваться в исходное решение о выполнении цикла, чтобы можно было построить очень сложную логическую систему. По словам, в ядре Linux есть много заявлений о Goto. Что касается того, почему вы по -прежнему часто слышите замечания, такие как высказывания Goto, просто Google сами.
5. Advanced Loop
5.1 Разверните петлю
Давайте сначала посмотрим на две части кода, и угадайте, у кого есть лучшая производительность.
Кода -копия выглядит следующим образом:
// Настраивать
var array = [
[«Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data»],
[«Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data»],
[«Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data»],
[«Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data»],
[«Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data»],
[«Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data»],
[«Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data»],
[«Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data», «Data»]
];
Функциональный процесс (элемент) {
// Сделай что -нибудь с предметом
}
// случай 1
for (var i = array.length-1; i> = 0; i--) {
for (var j = array [i] .length-1; j> = 0; i--) {
процесс (массив [i] [j]);
}
}
// случай 2
for (var i = array.length - 1; i> = 0; i = i - 4) {
for (var j = массив [i] .length - 1; j> = 0; j = j - 6) {
процесс (массив [i] [j]);
процесс (массив [i] [j - 1]);
процесс (массив [i] [j - 2]);
процесс (массив [i] [j - 3]);
процесс (массив [i] [j - 4]);
процесс (массив [i] [j - 5]);
}
for (var j = массив [i - 1] .length - 1; j> = 0; j = j - 6) {
процесс (массив [i] [j]);
процесс (массив [i] [j - 1]);
процесс (массив [i] [j - 2]);
процесс (массив [i] [j - 3]);
процесс (массив [i] [j - 4]);
процесс (массив [i] [j - 5]);
}
for (var j = массив [i - 2] .length - 1; j> = 0; j = j - 6) {
процесс (массив [i] [j]);
процесс (массив [i] [j - 1]);
процесс (массив [i] [j - 2]);
процесс (массив [i] [j - 3]);
процесс (массив [i] [j - 4]);
процесс (массив [i] [j - 5]);
}
for (var j = массив [i - 3] .length - 1; j> = 0; j = j - 6) {
процесс (массив [i] [j]);
процесс (массив [i] [j - 1]);
процесс (массив [i] [j - 2]);
процесс (массив [i] [j - 3]);
процесс (массив [i] [j - 4]);
процесс (массив [i] [j - 5]);
}
}
Мне нужно пройти через все элементы Subarray в массиве. Есть два решения, одно - это метод, который мы обычно используем, а другое - расширить задачу цикла. Ответ заключается в том, что дело 2 работает лучше, потому что все суждения о исполнении между каждыми 6 элементами удаляются, что естественно быстрее, чем обычно.
Здесь мы рассмотрим более мощное решение. Если бизнес -ссылка должна быть итеративно обработана на большом наборе данных, а объем данных не изменится с начала итерации, то вы можете рассмотреть возможность использования технологии, называемой Duff Device. Эта технология названа в честь его создателя Тома Даффа, который впервые был реализован на языке C. Позже Джефф Гринберг перенес его в JavaScript и изменил Эндрю b. Кинг и предложил более эффективную версию.
Кода -копия выглядит следующим образом:
// Кредит: ускорить ваш сайт (New Riders, 2003)
var iterations = math.floor (values.length / 8);
var Ofterover = values.length % 8;
var i = 0;
if (остаток> 0) {
делать {
процесс (значения [i ++]);
} while (-leftover> 0);
}
делать {
процесс (значения [i ++]);
процесс (значения [i ++]);
процесс (значения [i ++]);
процесс (значения [i ++]);
процесс (значения [i ++]);
процесс (значения [i ++]);
процесс (значения [i ++]);
процесс (значения [i ++]);
} while (-itherations> 0);
Принцип работы этого метода состоит в том, чтобы вычислить длину значений, деленные на 8, чтобы получить количество итераций, которые необходимо итерации, и использовать функцию Math.floor (), чтобы убедиться, что результат является целым числом, а затем рассчитайте число, которое не может быть делено на 8, и обрабатывает эти элементы отдельно, а затем 8 представляют собой единичную экспертику, чтобы изначально.
Я упаковал это устройство и получил API с асинхронным вкусом.
Кода -копия выглядит следующим образом:
функция Duff (массив, Mapper) {
var n = math.floor (array.length / 8);
var l = array.length % 8;
var i = 0;
if (l> 0) {
делать {
Mapper (массив [i ++]);
} while (--> 0);
}
делать {
Mapper (массив [i ++]);
Mapper (массив [i ++]);
Mapper (массив [i ++]);
Mapper (массив [i ++]);
Mapper (массив [i ++]);
Mapper (массив [i ++]);
Mapper (массив [i ++]);
Mapper (массив [i ++]);
} while (-n> 0);
}
Duff ([...], function (item) {
// ...
});
Вот набор тестов на производительность и результатов для приведенных выше трех итерационных решений. http://jsperf.com/spreaded-loop
5.2 Неснативная петля
На любом языке программирования можно реализовать петли не только косвенно другими способами, но и другими способами.
Давайте сначала рассмотрим некоторое содержание математики средней школы - общая формула последовательностей.
Кода -копия выглядит следующим образом:
Базовый
A [1] = 1
a [n] = 2 * a [n - 1] + 1
так
a [n] + 1 = 2 * a [n - 1] + 2
= 2 * (a [n - 1] + 1)
(a [n] + 1) / (a [n - 1] + 1) = 2
Затем
a [n] + 1 = (a [n] + 1) / (a [n - 1] + 1) * (a [n - 1] + 1) / (a [n - 2] + 1) * ... * (a [2] + 1) / (a [1] + 1) * (a [i] + 1)
a [n] + 1 = 2 * 2 * ... * 2 * 2
a [n] + 1 = 2^n
a [n] = 2^n - 1
Финал
a [n] = 2^n - 1
После прочтения простого расчета выше, вы, вероятно, догадайтесь, что мы собираемся обсудить. Да, мы также можем внедрить петли с использованием рекурсии.
Рекурсия является очень важным методом применения в математике и информатике, который относится к функции, вызывающей себя при использовании.
В сообществе Node.js рекурсия используется для реализации очень важной технологии: технологии промежуточного программного обеспечения. Это новая версия кода реализации промежуточного программного обеспечения в WebJS, которая еще не была опубликована.
Кода -копия выглядит следующим образом:
/**
* Метод запуска Middlewares
* @param {String} URL -URL -адрес текущего запроса
* @param {object} req объект запроса
* @param {object} res объект ответа
* @param {function} out полный обратный вызов
* @return {function} сервер
*/
server.runmiddlewares = function (url, req, res, out) {
var index = -1;
var middlewares = this._usingmiddlewares;
// запустить следующее промежуточное программное обеспечение, если оно существует
функция Next (err) {
index ++;
// текущее промежуточное программное обеспечение
var curr = middlewares [index];
if (curr) {
var check = new Regexp (curr.Route);
// Проверьте маршрут
if (check.test (url)) {
пытаться {
функция позже () {
отладка («промежуточное программное обеспечение говорит, что это должно быть позже на %s, url);
// зависимости сейчас не
if (middlewares.indexof (curr)! == middlewares.length - 1) {
_later (curr);
Индекс-;
следующий();
} еще {
отладка («неправильные зависимости промежуточного программного обеспечения»);
// это промежуточное программное обеспечение не может работать
вне();
}
}
// запустить промежуточное программное обеспечение
if (utils.isfunc (curr.handler)) {
// нормальная функция промежуточного программного обеспечения
curr.handler (req, res, затем, позже);
} else if (utils.isobject (curr.handler) && utils.isfunc (curr.handler.emit)) {
// объект сервера
curr.handler.emit ('request', req, res, затем, позже);
} еще {
// что -то не так в промежуточном программном обеспечении
следующий();
}
} catch (err) {
следующий();
}
} еще {
следующий();
}
} еще {
// Выйти к следующему шагу трубопровода
вне();
}
}
// Если промежуточное программное обеспечение зависит от других средних волн,
// это может позволить позже бежать
функция _later (curr) {
var i = middlewares.indexof (curr);
var _tmp1 = middlewares.slice (0, i);
_tmp1.push (middlewares [i + 1], curr);
var _tmp2 = middlewares.slice (i + 2);
[] .push.apply (_tmp1, _tmp2);
middlewares = _tmp1;
}
// первое промежуточное программное обеспечение
следующий();
вернуть это;
};
Хотя этот код выглядит суровым и сложным, будет намного яснее, если мы его упростим.
Кода -копия выглядит следующим образом:
server.runmiddlewares = function (url, req, res, out) {
var index = -1;
var middlewares = this._usingmiddlewares;
// запустить следующее промежуточное программное обеспечение, если оно существует
функция Next (err) {
index ++;
// текущее промежуточное программное обеспечение
var curr = middlewares [index];
if (curr) {
var check = new Regexp (curr.Route);
// Проверьте маршрут
if (check.test (url)) {
// запустить текущее промежуточное программное обеспечение
curr.handler (req, res, затем);
} еще {
следующий();
}
} еще {
// Выйти к следующему шагу трубопровода
вне();
}
}
// первое промежуточное программное обеспечение
следующий();
вернуть это;
};
Причина, по которой рекурсия может быть использована в реализации системы промежуточного программного обеспечения, заключается в том, что рекурсия является наиболее подходящим методом отклика программного потока в node.js.
В этом коде реализации промежуточного программного обеспечения This._UsingMiddleWares является массивом цикла, функция Next () является корпусом цикла, где Check.Test (url) является условием выполнения, а код обработки цикла является первым счетчиком индекса в корпусе цикла, чтобы увеличить на 1 и саму функцию.