函数调用自己setInterval(浏览器冻结问题)

function calling itself with setInterval (browser freezing issue)

本文关键字:冻结 问题 浏览器 自己 setInterval 函数调用      更新时间:2023-09-26

我知道已经有类似的问题了,但是我看到的答案没有一个能解决我的问题。

我写了一个小脚本,使用两个函数逐字母打印字符串:第一个函数拼写字符串,第二个函数调用第一个函数,只要单词没有完全拼写,使用setInterval:

function write() {
  writeThis = str.substring(0, currentLetter);
  div.innerHTML = writeThis;
  currentLetter++;
  console.log('running'); 
}
function start() {
  setInterval(function() {
    if (currentLetter > str.length) {
        return false;
    }
    write(); //calls the writing function
  }, 100);
}
start();

我需要将这两个函数合并为一个,以便通过传递字符串作为参数动态地在不同的字符串上使用它。我想做这样的事情:

function write(thisString) {
  //code
  return thisString;
}
var str1 = "hello world";
var str2 = "foo bar";
write(str1); write(str2);

当涉及到在write()函数中插入setInterval来调用自己时,我卡住了。无论我尝试什么,write()将永远调用自己(尽管if条件)并冻结浏览器。有可能把这两个功能合并成一个吗?

此处演示:https://jsfiddle.net/Hal_9100/b5gm8nbc/

setInterval会一直发射,直到你调用clearInterval(intervalId)

对于大多数动画,在任何情况下使用setTimeout都更容易控制,如下所示:

var div = document.getElementById('div');
var str = 'hello world.';
var currentLetter = 1;
var writeThis = str.substring(0, currentLetter);
function write() {
    writeThis = str.substring(0, currentLetter);
    div.innerHTML = writeThis;
    currentLetter++;
    console.log('running'); 
}
function run(){
    if (currentLetter > str.length) {
        return false;
    }
    write();
    setTimeout(run, 100);
}
function start() {
  setTimeout(run, 100);
}
start();

如果您真的想使用setInterval,该函数返回您需要的intervalId,因此您可以这样做:

var intervalId = setInterval(fn, 100);

则在if语句中调用

clearInterval(intervalId);

显然,您需要确保intervalId在两个地方都在作用域中。

** EDIT **

添加使其成为一个函数。抱歉我没听清问题的这一部分。这里的技巧是使用Function.bind()

var div = document.getElementById('div');
var str = 'hello world.';
var currentLetter = 1;
var writeThis = str.substring(0, currentLetter);
function run(text){
    if (currentLetter > text.length) {
        return false;
    }
    writeThis = text.substring(0, currentLetter);
    div.innerHTML = writeThis;
    currentLetter++;
    console.log('running');
    setTimeout(run.bind(null, text), 100);
}
run(str);

如果你想传递一切(例如div, str,当前字母),只需将它们作为参数添加到run函数,并在再次绑定时添加它们。

如果使用setInterval(),则必须使用clearInterval()清除间隔。

:

var interval = setInterval(function() {
    var i = 0;
    if(i < x) {
        ...
    } else {
        clearInterval(interval);
    }
});
总:

var div = document.getElementById("myDiv");
var str = "Hello world!";
function write(str) {
  var i = 0;
  var len = str.length;
  var interval = setInterval(function() {
    if (i < len) {
      div.innerHTML += str[i];
    } else {
      clearInterval(interval);
    }
    i += 1;
  }, 100);
}
write(str);
<div id="myDiv"></div>

下面是使用Element.typeEffect("Hello World");的示例原型

更新:最好使用textContent而不是innerHTML来将字符串写为文本而不是HTML。

:

  • 如果你想使用多个div的函数,避免使用递增的数字作为全局变量
  • 在使用此函数之前,您的#div应该为空。
  • 你可以使用callback在写完后触发。

var div = document.getElementById('div');
var div2 = document.getElementById('div2');
Element.prototype.typeEffect = function(str, onfinish) {
  var el = this;
  var i = el.textContent || el.innerText;
  i = i.length;
  if (i == str.length) {
    if (typeof onfinish == "function") onfinish();
    return;
  }
  el.textContent += str[i];
  setTimeout(function() {
    el.typeEffect(str, onfinish);
  }, 100);
}
div.typeEffect("Hello World");
//optinaly callback
div2.typeEffect("Helo Again", function() {
  console.log("#div2 finished");
});
<div id="div"></div>
<hr/>
<div id="div2"></div>

如果你不喜欢原型,试试这个

function typeEffect(str,el,cb) {
  var i = el.textContent || el.innerText;
  i = i.length;
  if (i == str.length){
  if(typeof cb == "function")cb();
    return;    
  }
  el.textContent += str[i];
  setTimeout(function() {
    typeEffect(str,el,cb);
  }, 100);
}
//usage
typeEffect("Hello World",div);
//or with callback
typeEffect("Hello World",div,function(){
console.log("finished");
});