У меня есть сценарий (упрощенный в примере ниже), где действие пользователя инициирует рекурсивную функцию.
Пользователь может инициировать новое действие в то время, когда уже начатые действия еще не закончены.
Но я хотел бы гарантировать, что любое новое действие прекратит все предыдущие действия.
То, что на самом деле происходит в настоящее время (вы можете видеть это в приведенном ниже примере), заключается в том, что независимо от количества новых действий, инициируемых пользователем, каждое из ранее инициированных действий продолжается до тех пор, пока оно не закончится.
Я хотел бы знать, можно ли (в приведенном ниже примере) начать выращивать новый список, когда предыдущий список вырос только до 5 пунктов и обеспечить, чтобы предыдущий список не стал больше.
var trigger = document.getElementsByTagName('p')[0];
var o = 0;
function addListItems(orderedList, listItemNumber) {
var listItems = orderedList.getElementsByTagName('li');
if (listItemNumber > 9) {
return;
}
listItems[listItemNumber].classList.add('show');
listItemNumber++;
setTimeout(function(){addListItems(orderedList, listItemNumber)}, 400);
}
function startRecursiveFunction() {
var orderedList = document.getElementsByTagName('ol')[o];
var listItemNumber = 0;
if (o < 7) {
addListItems(orderedList, listItemNumber);
}
o++;
}
trigger.addEventListener('click', startRecursiveFunction, false);
p {
font-weight: bold;
cursor: pointer;
}
ol {
display: inline-block;
}
li {
opacity: 0;
}
li.show {
opacity: 1;
}
<p>Click to trigger function (up to 7 times)</p>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
Вы можете использовать переменную счетчика, которая будет увеличена при каждом startRecursiveFunction
. В setTimeout
вы проверяете, изменился счетчик, и если это так, вы прекратите рекурсию.
var trigger = document.getElementsByTagName('p')[0];
var o = 0;
var fnId = 0;
function addListItems(orderedList, listItemNumber) {
var listItems = orderedList.getElementsByTagName('li');
if (listItemNumber > 9) {
return;
}
listItems[listItemNumber].classList.add('show');
listItemNumber++;
var lastFnId = fnId;
setTimeout(function() {
if (lastFnId === fnId) {
addListItems(orderedList, listItemNumber);
}
}, 400);
}
function startRecursiveFunction() {
var orderedList = document.getElementsByTagName('ol')[o];
var listItemNumber = 0;
if (o < 7) {
fnId++;
addListItems(orderedList, listItemNumber);
}
o++;
}
trigger.addEventListener('click', startRecursiveFunction, false);
p {
font-weight: bold;
cursor: pointer;
}
ol {
display: inline-block;
}
li {
opacity: 0;
}
li.show {
opacity: 1;
}
<p>Click to trigger function</p>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
Вы можете использовать clearTimeout
для отмены запланированного события тайм-аута.
Обратите внимание на три изменения вашего кода, отмеченные знаком ***
, которые касаются новой переменной timer
:
var trigger = document.getElementsByTagName('p')[0];
var o = 0;
var timer; //***
function addListItems(orderedList, listItemNumber) {
var listItems = orderedList.getElementsByTagName('li');
if (listItemNumber > 9) {
return;
}
listItems[listItemNumber].classList.add('show');
listItemNumber++;
// ***
timer = setTimeout(function(){addListItems(orderedList, listItemNumber)}, 400);
}
function startRecursiveFunction() {
var orderedList = document.getElementsByTagName('ol')[o];
var listItemNumber = 0;
clearTimeout(timer); // ***
if (o < 7) {
addListItems(orderedList, listItemNumber);
}
o++;
}
trigger.addEventListener('click', startRecursiveFunction, false);
p {
font-weight: bold;
cursor: pointer;
}
ol {
display: inline-block;
}
li {
opacity: 0;
}
li.show {
opacity: 1;
}
<p>Click to trigger function (up to 7 times)</p>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ol>
Однако я должен добавить, что это не настоящая рекурсия: стек вызовов не растет с каждым вызовом addListItems
, так как предыдущий вызов уже закончился, когда следующий инициируется через событие setTimeout
: стек вызовов пуст между таких звонков.
Это была настоящая (синхронная) рекурсия, не было бы ничего, что вы могли бы сделать с событиями кликов, поскольку эти вызовы вызова не будут вызываться до тех пор, пока не закончится рекурсия.
setTimeout
и clearTimeout
, но не смог заставить их работать успешно в случае моей (довольно сложной) установки. Тем не менее, я признаю, что это был бы нормальный способ приблизиться к прекращению повторяющихся процессов на ранней стадии.