likes
comments
collection
share

死循环===栈溢出?先有问题再有答案 什么是死循环? 死循环有什么影响? js中实现死循环的方式有几种? 死循环页面一定

作者站长头像
站长
· 阅读数 35

先有问题再有答案

  1. 什么是死循环?
  2. 死循环有什么影响?
  3. js中实现死循环的方式有几种?
  4. 死循环页面一定会卡死嘛?
  5. 死循一定会导致栈溢出嘛?
  6. 死循环代表代码错误嘛?
  7. 无限循环有哪些应用场景?

死循环===栈溢出?先有问题再有答案 什么是死循环? 死循环有什么影响? js中实现死循环的方式有几种? 死循环页面一定

死循环

在JavaScript中,死循环是指一种无法自行结束的循环。一般来说,循环会在满足某种条件时自动结束,比如for循环会在循环次数到达一定数量时结束,while循环会在条件不再满足时结束。但是,如果循环的结束条件没有被正确地设计或实现,那么循环可能永远无法自行结束,这就是死循环。

for(let i = 0; i >= 0; i++){ // 这里是循环体 }

上面的例子中,i的初始值为0,并且在每次循环执行后,i的值都会增加1,那么i的值永远都会大于等于0,因此,这个for循环的结束条件i >= 0永远无法满足,这是一个死循环。

while(true){ // 这里是循环体 }

在上面的例子中,由于while循环的条件直接写成了常量true,所以它永远满足,导致while循环无法自行结束,这是一个死循环。

死循环的影响:

  1. 用户体验差:JavaScript是运行在浏览器的,当一个死循环运行时,它将使得浏览器无法响应用户的交互行为,导致页面卡死,生成“页面无响应”的错误。
  2. CPU占用过高:死循环将导致CPU满载运转,这将严重拖慢计算机的运行速度,甚至导致计算机无法正常运行。
  3. 内存消耗增加:如果在循环中进行大量数据的处理或者对象的创建,可能会导致内存消耗过大,甚至出现内存泄漏,造成浏览器崩溃。
  4. 电能消耗:长时间运行死循环会使得计算机无法进入待机状态,引起不必要的电能消耗。
  5. 代码的健壮性:程序代码出现死循环,通常是程序设计上的错误,表明代码的健壮性、鲁棒性有待提高。

因此在编写JavaScript代码时,需要避免死循环的产生,保证循环有明确的退出条件。必要时可以设置迭代限制,防止可能的死循环。

死循环的N种方式

通常来说,死循环的存在往往是程序设计上的错误,并没有优点。因为它会浪费系统资源,占用大量的CPU性能,甚至可能导致系统崩溃。

然而,在某些特定的情况下,我们可能会使用类似死循环的能力。

分帧动画

let xPos = 0;
function loop() {
  xPos += 5; // 改变位置

  if (xPos > window.innerWidth) {
    xPos = 0;
  }

  // 改变元素位置
  document.getElementById("myElement").style.left = xPos + "px";

  requestAnimationFrame(loop); // 在下一个刷新周期调用loop
}

// 在下一个刷新周期调用loop
requestAnimationFrame(loop);

上述代码,requestAnimationFrame(loop)使得loop函数将在下一次界面刷新时被调用,并且它在每次调用完毕后又调用了自身,建立了一个持续的刷新循环。

requestAnimationFrame的优点是它会在浏览器下个刷新周期自动调用,与浏览器绘制的频率同步,可以保证动画的流畅性,并且当页面不可见或最小化时,动画会自动暂停,可以有效节省CPU开销和电能。

与标准的“死循环”不同,这个模式可以被浏览器控制,是在动画或游戏开发中常见的工作模式,是一种被提倡的动画开发方式之一.

计时器循环

let timer;
function loop() {
    if(timer){
        clearTimeout(timer)
    }
    // 执行一些业务逻辑
    timer = setTimeout(loop, 1000);
}
loop()

这段代码实现了一个死循环。它通过递归地设置一个 setTimeout 来不断调用 loop 函数,从而形成一个无限循环。每次 loop 被调用时,它都会清除上一个定时器(如果存在的话),然后设置一个新的定时器,1秒后再次调用 loop 函数。

这种类型的循环通常用于以下应用场景:

  1. 定时任务:定期执行某些操作,比如每隔一定时间检查服务器的状态、更新UI元素、发送心跳信号等。
  2. 长轮询:在WebSocket不可用的情况下,作为一种与服务器保持通信的方式,客户端定期发送请求到服务器,服务器在有更新时立即响应
  3. 动画帧控制:在之前的动画制作中,大家对requestAnimationFrame还不太了解 大部分是通过计时器定期更新画面来创建平滑的动画效果。
  4. 资源释放:在某些情况下,可能需要定期检查和释放不再使用的资源。
  5. 监控需要:用于实现监控数据的收集。在监控系统中,通常需要定期收集系统或应用程序的性能指标、日志信息、资源使用情况等数据。使用 setTimeout 来实现循环可以确保这些数据在固定的时间间隔内被收集。

Generator循环

function* trafficLight() {
    while (true) {
        yield { color: 'green', duration: 5000 };
        yield { color: 'yellow', duration: 3000 };
        yield { color: 'red', duration: 2000 };
    }
}

const light = trafficLight();

function changeLight() {
    const state = light.next().value;
    console.log(state.color);
    setTimeout(changeLight, state.duration);
}

changeLight();

这段代码是利用JavaScript的Generator函数和yield关键词来模拟一个交通灯的逻辑。

Generator函数的特性是可以暂停和恢复执行,yield关键字可以让Generator函数暂停执行并返回一个值,再次调用next方法时又从上次暂停的地方恢复执行。

这段代码trafficLight函数内部有一个无限循环,模拟了交通灯不停变化的过程。每次循环都依次返回一个对象,代表了交通灯的状态(颜色)和持续的时间。

  1. 第一次调用trafficLight().next()之后,遇到第一个yield,返回一个对象{ color: 'green', duration: 5000 },交通灯变为绿色,持续时间为5000毫秒。
  2. 第二次调用trafficLight().next()时,会从第一个yield后面继续执行,直到遇到第二个yield,返回一个对象{ color: 'yellow', duration: 3000 },交通灯变为黄色,持续时间为3000毫秒。
  3. 第三次调用trafficLight().next()时,继续执行,遇到第三个yield,返回一个对象{ color: 'red', duration: 2000 },交通灯变为红色,持续时间为2000毫秒。
  4. 第四次调用trafficLight().next()时,因为是在循环中,所以会再次从头开始执行,返回绿灯的状态。

所以,这段代码的逻辑就是模拟了一个交通灯颜色不断轮换的过程,绿灯→黄灯→红灯→绿灯→黄灯→红灯......,并且每种颜色的灯持续的时间也是固定的。

同步、异步死循环

 function btn() {
        console.log('test btn');
        // btn(); 第一种情况 同步死循环
        // setTimeout(btn,0) 第二种情况 异步宏任务死循环
        // Promise.resolve().then(btn) 第三种情况 异步微任务死循环
       
    }
btn();

参考

转载自:https://juejin.cn/post/7411833413668732955
评论
请登录