for ループ内の setTimeout [重複]
-
21-09-2019 - |
質問
この質問にはすでに答えがあります:
次のコードを使用して、文字列を 1 文字ずつ表示したいとします。
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
for(c = 0; c < text.length; c++)
{
setTimeout('textScroller.innerHTML += text[c]', 1000);
}
}
window.onload = initText;
動いていない..私は何を間違っているのでしょうか?
解決
このような何かを試してみてください
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
var interval = setInterval(function() {
textScroller.innerHTML += text[c];
c++;
if(c >= text.length) clearInterval(interval);
}, 1000);
}
注私はそれが必要だときにそれを停止するclearInterval
を追加します。
他のヒント
現在、あなたは18のタイムアウトを定義しているし、すべてを一度に〜実行されます。 第二の問題は、あなたが文字列として実行する命令を渡し、です。評価されたコードは、グローバルスコープで実行されますので、その場合は、コードは、initTextで定義されているすべての変数にアクセスすることはできません。
IMO、これは仕事を行う必要があります。
function initText(){
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
(function(){
textScroller.innerHTML += text.charAt(c++);
if(text.length > c){
setTimeout(arguments.callee, 1000);
}
})();
}
Timeout
を使用して
var repeat = (function () {
return function repeat(cbWhileNotTrue, period) {
/// <summary>Continuously repeats callback after a period has passed, until the callback triggers a stop by returning true. Note each repetition only fires after the callback has completed. Identifier returned is an object, prematurely stop like `timer = repeat(...); clearTimeout(timer.t);`</summary>
var timer = {}, fn = function () {
if (true === cbWhileNotTrue()) {
return clearTimeout(timer.t); // no more repeat
}
timer.t = setTimeout(fn, period || 1000);
};
fn(); // engage
return timer; // and expose stopper object
};
})();
var repeat = (function () {
return function repeat(cbWhileNotTrue, period) {
/// <summary>Continuously repeats callback after a period has passed, until the callback triggers a stop by returning true. Note each repetition only fires after the callback has completed. Identifier returned is an object, prematurely stop like `timer = repeat(...); clearTimeout(timer.t);`</summary>
var timer = {}, fn = function () {
if (true === cbWhileNotTrue()) {
return clearTimeout(timer.t); // no more repeat
}
timer.t = setTimeout(fn, period || 1000);
};
fn(); // engage
return timer; // and expose stopper object
};
})();
Interval
を使用して
var loop = (function () {
return function loop(cbWhileNotTrue, period) {
/// <summary>Continuously performs a callback once every period, until the callback triggers a stop by returning true. Note that regardless of how long the callback takes, it will be triggered once per period.</summary>
var timer = setInterval(function () {
if (true === cbWhileNotTrue()) clearInterval(timer);
}, period || 1000);
return timer; // expose stopper
};
})();
var loop = (function () {
return function loop(cbWhileNotTrue, period) {
/// <summary>Continuously performs a callback once every period, until the callback triggers a stop by returning true. Note that regardless of how long the callback takes, it will be triggered once per period.</summary>
var timer = setInterval(function () {
if (true === cbWhileNotTrue()) clearInterval(timer);
}, period || 1000);
return timer; // expose stopper
};
})();
2の間のわずかな違いは、コメントで示されている - repeat
方法は、あなたが持っている場合ので、「遅い」それはすべてのdelay
ミリ秒を実行しませんコールバックが、の繰り返しの、コールバックを実行した後に繰り返されます実行の間、すべてのdelay
後、loop
法に対しコールバック毎delay
ミリ秒を起動します。早期に停止する、repeat
代わりに返される識別子としてオブジェクトを使用するため、使用clearTimeout(timer.t)
。
使用方法:
と同じように、@ soufiane-hassouによって回答するます:
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
var interval = repeat/* or loop */(function() {
textScroller.innerHTML += text[c];
c++;
return (c >= text.length);
}, 1000);
のように述べたように、時期尚早停止は以下のようになります:
/* if repeat */ clearTimeout(interval.t);
/* if loop */ clearInterval(interval);
これを試してみてください
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
for(c = 0; c < text.length; c++)
{
setTimeout("textScroller.innerHTML += '" + text[c] + "'", 1000 + c*200);
}
}
window.onload = initText;
クロージャを使用してみてください
function init() {
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
function run() {
textScroller.innerHTML += text[c++];
if (c<text.length)
setTimeout(run, 1000);
}
setTimeout(run, 1000);
}
init()
あなたのコード内の問題は、文字列に入れたコードがtextScrollerが(それはあなたの関数内で定義されている)に定義されていないグローバルコンテキストで実行されるということです。
私は(Soufiane Hassouによって回答に基づいて)スニペットを共有したいです。あなたは文字通り一定の時間間隔でいくつかのアレイの上に反復するforループ体を交換するときにケースにまで及びます。基本的には同じ同期ループが、「スリープ」(ジャバスクリプトは、同期のプログラミング言語ではないので)一時停止ます。
とfunction loop(arr, take, period) {
period = period || 1000;
var i = 0;
var interval = setInterval(function() {
take(i, arr[i]);
if (++i >= arr.length) { clearInterval(interval);}
}, period);
}
使用例:
loop([1, 2, 3, 4], function(index, elem){
console.log('arr[' + index + ']: ' + elem);
});
ノードJSでテストされています。誰かに役立ちます願っています。
の編集> の
次の更新が可能(jQueryのかプロトタイプのような)重い「プロトタイピング」をやってLIBSとコード使える一緒ます:
function loop(arr, take, period) {
period = period || 1000;
var scope = {
i: 0,
arr: arr,
take: take,
};
var iterate = (function iterate() {
if (this.i >= this.arr.length) { clearInterval(this.interval); return}
take(this.i, this.arr[this.i++]);
}).bind(scope);
scope.interval = setInterval(iterate, period);
}
あなたのforループは、一度にすべての彼らは順番に表示されませんので、一度にすべての文字のタイムアウトを設定しますが、されています。あなたのsetTimeoutは、ディスプレイに次の文字が含まれます別のsetTimeoutのコードが含まれている必要があります。
このような何かが(これをテストしていない)ので、
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
setTimeout('nextChar(text)', 1000);
}
function nextChar(text){
if(text.length > 0){
textScroller.innerHTML += text[0];
setTimeout('nextChar(text.substring(1))', 1000);
}
}
、これが役に立つことができます:
var b = {
textScroller: document.getElementById('textScroller'),
text: "Hello how are you?"
};
function initText() {
for(c = 0; c < b.text.length; c++) {
setTimeout("append("+c+")", 1000 + c*200);
}
}
function append(c) {
b.textScroller.innerHTML += b.text[c];
}
window.onload = initText;
もし上記のアペンド関数にパラメータを渡すことができますしてます。
次のコードは、トリックを行い、いくつかのパラメータを渡します
var glo = [];
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = "Hello how are you?";
var timeout_time;
for(c = 0; c < text.length; c++) {
glo[glo.length] = {text:text, c:c, textScroller:textScroller};
timeout_time = 1000 + c * 200;
setTimeout("append(" + (glo.length - 1) + ")", timeout_time);
}
}
function append(i)
{
var obj = glo[i];
obj.textScroller.innerHTML += obj.text[obj.c];
obj = null;
glo[i] = null;
}
window.onload = initText;
もし上記の唯一のグローバル配列glo
を持っていると。ループでは、パラメータとして渡されたインデックスを使用して、これらのメンバを参照glo
へとappend()
機能で新しいアレイメンバーを作成します。
注意:2番目のコードサンプルはOPに最高または最適なソリューションとしてのものではありません。■問題が、他のsetTimeout相対的な問題、例えばで利益を得ることができます。誰かがいくつかの機能はいくつかの遅延の後に呼び出すために必要なプレゼンテーションやパフォーマンステストをしようとするとき。このコードの利点は、タイムアウト機能へのループ時の状態に「送信」ローカル変数にも内部ループや能力を使用するために、ループのための使用(多くのプログラマーがループに使用する)と可能性を作ることです。
カスケードに優れてループすることであってもよいです。 exempleはdiv要素をフェードさせるには:
div=document.createElement('div');
div.style.opacity=1;
setTimeout(function(){fade(1);},3000);
function fade(op){
op-=.05;
if(op>0) setTimeout(function(){div.style.opacity=op;fade(op);},30);
else document.body.removeChild(div);
}