每秒刷新日期的功能最终会使Chrome崩溃



>我有几个函数来获取日期和时间,然后将它们推送到 DOM 中的元素。它似乎运行良好,直到几分钟后脚本耗尽内存并导致页面崩溃。这是我认为影响我的问题的代码:

'use strict';
// ///////////////////////////// INITIAL /////////////////////////////////// //
function leading_0( num ) {
  if( num < 10 ) {
    num = '0' + num;
  }
  
  return num;
}
// ////////////////////////////// DATES //////////////////////////////////// //
function getCurrentTime( date ) {  // TIME / / / / / / / / / / / / / / / / / //
  var hours = date.getHours(),
      minutes = date.getMinutes(),
      seconds = date.getSeconds(),
      suffix = hours >= 12 ? 'PM' : 'AM',
      fullTime;
  hours = hours % 12;
  if( hours === 0 ){
    hours = 12;
  }
  minutes = leading_0( minutes );
  seconds = leading_0( seconds );
  fullTime = hours + ':' + minutes + ':' + seconds + ' ' + suffix;
  return fullTime;
}  // \/ / / / / / / / / / / / / / / TIME / / / / / / / / / / / / / / / / / //
function getYear( date ) {  /// / / / YEAR / / / / / / / / / / / / / / / / / //
  var year = date.getFullYear();
  return year;
}  // \/ / / / / / / / / / / / / / / YEAR / / / / / / / / / / / / / / / / / //
function getMonthDay( date ) {  /// MONTH DAY / / / / / / / / / / / / / / / ///
  var day = date.getDate();
  return day;
}  // \/ / / / / / / / / / / / / / MONTH DAY / / / / / / / / / / / / / / / ///
function getMonth( date ) {  // / / / MONTH / / / / / / / / / / / / / / / / ///
  var months = [
    'January', 'Feburary', 'March',
    'April', 'May', 'June',
    'July', 'August', 'September',
    'October', 'November', 'December'
  ],
  month = months[ date.getMonth() ];
  return month;
}  // \/ / / / / / / / / / / / / / / MONTH / / / / / / / / / / / / / / / / ///
function getWkDay( date ) {  /// / / WEEK DAY / / / / / / / / / / / / / / / ///
  var weekdays = [ 
    'Sunday', 'Monday', 
    'Tueday', 'Wednesday', 
    'Thursday', 'Friday', 
    'Saturday' 
  ],
  wkDay = weekdays[ date.getDay() ];
  return wkDay;
}  // \ / / / / / / / / / / / / / / WEEK DAY / / / / / / / / / / / / / / / ///
function callBySec( func ) {
  setInterval( func, 1000 );
}
function pushDate(){  /// / / / / / PUSH DATES / / / / / / / / / / / / / / / //
  var today = new Date(),
      wkDay,
      month,
      day,
      year,
      time,
      d = document;
    
  wkDay = getWkDay( today );
  month = getMonth( today );
  day = getMonthDay( today );
  year = getYear( today );
  time = getCurrentTime( today );
  
  d.getElementById( 'wkDay' ).textContent = wkDay;
  d.getElementById( 'month' ).textContent = month;
  d.getElementById( 'day' ).textContent = day;
  d.getElementById( 'year' ).textContent = year;
  d.getElementById( 'time' ).textContent = time;
  
  callBySec( pushDate );
}  // \/ / / / / / / / / / / / / / PUSH DATES / / / / / / / / / / / / / / / //
// ////////////////////////////// START //////////////////////////////////// //
function start() {
  pushDate();
}
start();
<p>
  <span id="wkDay"></span>, 
  <span id="month"></span> <span id="day"></span>, 
  <span id="year"></span> <b>|</b> <span id="time"></span>
</p>

上面的代码是主要的内存消耗吗?即使在这个SO页面上,它最终也会使chrome崩溃。有没有更好的方法来做到这一点并获得相同的结果?

去掉这一行:

callBySec( pushDate );

pushDate()结束时.您已经在使用 setInterval() 每秒调用函数,无需再次启动计时器。结果是,您每秒都会创建另一个计时器。一分钟后,您每秒运行该函数 60 次。

如果callBySec使用setTimeout()而不是setInterval(),您的代码是正确的。

那么start()函数应该调用callBySec

'use strict';
function leading_0(num) {
  if (num < 10) {
    num = '0' + num;
  }
  return num;
}
function getCurrentTime(date) {
  var hours = date.getHours(),
    minutes = date.getMinutes(),
    seconds = date.getSeconds(),
    suffix = hours >= 12 ? 'PM' : 'AM',
    fullTime;
  hours = hours % 12;
  if (hours === 0) {
    hours = 12;
  }
  minutes = leading_0(minutes);
  seconds = leading_0(seconds);
  fullTime = hours + ':' + minutes + ':' + seconds + ' ' + suffix;
  return fullTime;
} 
function getYear(date) {
  var year = date.getFullYear();
  return year;
} 
function getMonthDay(date) { 
  var day = date.getDate();
  return day;
} 
function getMonth(date) { 
  var months = [
      'January', 'Feburary', 'March',
      'April', 'May', 'June',
      'July', 'August', 'September',
      'October', 'November', 'December'
    ],
    month = months[date.getMonth()];
  return month;
} 
function getWkDay(date) { 
  var weekdays = [
      'Sunday', 'Monday',
      'Tueday', 'Wednesday',
      'Thursday', 'Friday',
      'Saturday'
    ],
    wkDay = weekdays[date.getDay()];
  return wkDay;
}
function callBySec(func) {
  setInterval(func, 1000);
}
function pushDate() { 
  var today = new Date(),
    wkDay,
    month,
    day,
    year,
    time,
    d = document;
  wkDay = getWkDay(today);
  month = getMonth(today);
  day = getMonthDay(today);
  year = getYear(today);
  time = getCurrentTime(today);
  d.getElementById('wkDay').textContent = wkDay;
  d.getElementById('month').textContent = month;
  d.getElementById('day').textContent = day;
  d.getElementById('year').textContent = year;
  d.getElementById('time').textContent = time;
} 
function start() {
  callBySec(pushDate);
}
start();
<p>
  <span id="wkDay"></span>,
  <span id="month"></span> <span id="day"></span>,
  <span id="year"></span> <b>|</b> <span id="time"></span>
</p>

尝试使用 setTimeout() 而不是 setInterval(),因为后者会创建一个重复的执行路径,而前者只是在将来的设定时间运行一次代码块。

正如您所拥有的那样,每秒您都会将pushDate()重复执行的数量增加一倍。

我完全希望这是 OOM,因为您使用的是递归,并且永远不会爆发。

问题是你最终得到的调用链

pushDate -> callBySec -> pushDate -> callBySec -> PushDate -> etc

无限。

你应该做的是完全摆脱callBySec,并改变你的启动方法以使用setInterval本身,而不是依赖递归(你目前每秒启动一个新的计时器(。

function start() {
    setInterval(pushDate, 1000);
}

setInterval(( 方法以指定的时间间隔(以毫秒为单位(调用函数或计算表达式。 setInterval(( 方法将继续调用该函数,直到调用 clearInterval(( 或关闭窗口。

取自 https://www.w3schools.com/jsref/met_win_setinterval.asp

所以,基本上,你调用你的函数pushDate,它会启动一个计时器来每秒调用你的函数,每个调用的函数都会启动另一个间隔。

如果您在 start 函数中调用 intervall - 而不是递归 - 那就没问题了。

最新更新