是否可以通过该函数之外的操作退出javascript中的递归函数?

时间:2018-02-11 21:39:52

标签: javascript function exit

我有一个脚本(在下面的示例中简化),其中用户操作启动递归函数。

用户可以在已启动的操作尚未完成运行时启动新操作。

但我想确保任何新动作停止以前的所有操作

目前实际发生的事情(您可以在下面的示例中看到这一点)是,无论用户启动了多少新操作,每个先前启动的操作都会继续,直到完成为止。

我想知道是否(在下面的例子中)当前一个列表只增加了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>

2 个答案:

答案 0 :(得分:3)

您可以使用clearTimeout取消已安排的超时事件。

请注意标有***的代码的三处更改,这些更改都处理新的timer变量:

&#13;
&#13;
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);
&#13;
p {
font-weight: bold;
cursor: pointer;
}

ol {
display: inline-block;
}

li {
opacity: 0;
}

li.show {
opacity: 1;
}
&#13;
<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>
&#13;
&#13;
&#13;

但是,我应该补充一点,这不是真正的递归:调用堆栈不会随着每次调用addListItems而增长,因为前一次调用已经在通过{{启动下一个调用时已经结束事件:在这些调用之间调用堆栈是空的。

它是真正的(同步)递归,你可以对点击事件做任何事情,因为直到递归完成后才会调用那些事件回调。

答案 1 :(得分:2)

您可以使用计数器变量,每次调用startRecursiveFunction时都会增加该变量。在setTimeout回调中,检查计数器是否已更改,如果是,则停止递归。

&#13;
&#13;
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);
&#13;
p {
font-weight: bold;
cursor: pointer;
}

ol {
display: inline-block;
}

li {
opacity: 0;
}

li.show {
opacity: 1;
}
&#13;
<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>
&#13;
&#13;
&#13;