JavaScriptのsetTimeoutとsetIntervalをラッピングし、使い勝手を統一したLibrary
JavaScriptには遅延実行を行うためのメソッドが二つ存在する。
windowオブジェクトに属するsetTimeoutとsetIntervalである。
setTimeoutは一定時間後に処理を、setIntervalは一定時間間隔で処理を実行させる。
つまり、同じ処理を何度も繰り返す場合、大きく二通りのやり方が考えられる。
windowオブジェクトに属するsetTimeoutとsetIntervalである。
setTimeoutは一定時間後に処理を、setIntervalは一定時間間隔で処理を実行させる。
つまり、同じ処理を何度も繰り返す場合、大きく二通りのやり方が考えられる。
textareaに乱数を書き出す(setTimeoutの場合)
function timer(){
document.getElementById("output").value+=Math.random()+"\n";
setTimeout(timer,1000);
}
timer();
document.getElementById("output").value+=Math.random()+"\n";
setTimeout(timer,1000);
}
timer();
textareaに乱数を書き出す(setIntervalの場合)
function timer(){
document.getElementById("output").value+=Math.random()+"\n";
}
setInterval(timer,1000);
document.getElementById("output").value+=Math.random()+"\n";
}
setInterval(timer,1000);
上記例では、ほとんど問題にならないが、両者では処理にかかる時間によって出力の間隔が若干異なり、
setTimeoutは「固定遅延実行」、setIntervalは「固定頻度実行」となる。
ほとんど同じ処理にもかかわらず、「固定遅延実行」と「固定頻度実行」の違いだけで、記述方法を変えなければならないのはなんとも面倒だ。
両者の違いを吸収し、使い勝手を統一するLibraryを作成した。
setTimeoutは「固定遅延実行」、setIntervalは「固定頻度実行」となる。
ほとんど同じ処理にもかかわらず、「固定遅延実行」と「固定頻度実行」の違いだけで、記述方法を変えなければならないのはなんとも面倒だ。
両者の違いを吸収し、使い勝手を統一するLibraryを作成した。
/*
================================================================================
Name : TimerUtility
In : [none]
Out : [none]
Note : タイマー用ユーティリティ群
--------------------------------------------------------------------------------
Version : Ver0.1.0 | 2007/08/12 | 新規作成
--------------------------------------------------------------------------------
License : MIT license
URL : www.kanasansoft.com
================================================================================
*/
/*--------------------------------------------------------------------------------
コンストラクタ
--------------------------------------------------------------------------------*/
function TimerUtility(){
}
TimerUtility.Timeout
= function(arg){
this._ontimer = arg["ontimer"] ;
this._count = arg["count"] ;
this._msec = arg["msec"] ;
this._onend = arg["onend"] ;
this._onstop = arg["onstop"] ;
this._counter = 0 ;
this._result = [] ;
}
TimerUtility.Interval
= function(arg){
this._ontimer = arg["ontimer"] ;
this._count = arg["count"] ;
this._msec = arg["msec"] ;
this._onend = arg["onend"] ;
this._onstop = arg["onstop"] ;
this._counter = 0 ;
this._result = [] ;
}
/*--------------------------------------------------------------------------------
TimeoutのClosure
--------------------------------------------------------------------------------*/
TimerUtility.Timeout._closure=function(arg){
var _scope = arg["scope"] ;
var _arg = arg["args"] ;
return function(){_scope.start.apply(_scope,_arg)};
}
/*--------------------------------------------------------------------------------
Timeoutの開始処理(実行毎に呼び出される)
--------------------------------------------------------------------------------*/
TimerUtility.Timeout.prototype.start
= function(){
if(this._counter<this._count){
this._counter++;
var result=this._ontimer.apply(this,arguments);
this._result.push(result);
if(this._onend){
this._onend(result);
}
this._id=setTimeout(
this.constructor._closure(
{ "scope" : this ,
"args" : arguments }
)
,this._msec
);
}else{
this.stop();
}
}
/*--------------------------------------------------------------------------------
Timeoutの終了処理
--------------------------------------------------------------------------------*/
TimerUtility.Timeout.prototype.stop
= function(){
clearTimeout(this._id);
if(this._onstop){
this._onstop(this._result);
}
}
/*--------------------------------------------------------------------------------
IntervalのClosure
--------------------------------------------------------------------------------*/
TimerUtility.Interval._closure=function(arg){
var _scope = arg["scope"] ;
var _arg = arg["args"] ;
return function(){
if(_scope._counter<_scope._count){
_scope._counter++;
var result=_scope._ontimer.apply(_scope,_arg);
_scope._result.push(result);
if(_scope._onend){
_scope._onend(result);
}
}else{
_scope.stop();
}
};
}
/*--------------------------------------------------------------------------------
Intervalの開始処理(開始時に呼び出される)
--------------------------------------------------------------------------------*/
TimerUtility.Interval.prototype.start
= function(){
this._id=setInterval(
this.constructor._closure(
{ "scope" : this ,
"args" : arguments }
)
,this._msec
);
}
/*--------------------------------------------------------------------------------
Intervalの終了処理
--------------------------------------------------------------------------------*/
TimerUtility.Interval.prototype.stop
= function(){
clearInterval(this._id);
if(this._onstop){
this._onstop(this._result);
}
}
================================================================================
Name : TimerUtility
In : [none]
Out : [none]
Note : タイマー用ユーティリティ群
--------------------------------------------------------------------------------
Version : Ver0.1.0 | 2007/08/12 | 新規作成
--------------------------------------------------------------------------------
License : MIT license
URL : www.kanasansoft.com
================================================================================
*/
/*--------------------------------------------------------------------------------
コンストラクタ
--------------------------------------------------------------------------------*/
function TimerUtility(){
}
TimerUtility.Timeout
= function(arg){
this._ontimer = arg["ontimer"] ;
this._count = arg["count"] ;
this._msec = arg["msec"] ;
this._onend = arg["onend"] ;
this._onstop = arg["onstop"] ;
this._counter = 0 ;
this._result = [] ;
}
TimerUtility.Interval
= function(arg){
this._ontimer = arg["ontimer"] ;
this._count = arg["count"] ;
this._msec = arg["msec"] ;
this._onend = arg["onend"] ;
this._onstop = arg["onstop"] ;
this._counter = 0 ;
this._result = [] ;
}
/*--------------------------------------------------------------------------------
TimeoutのClosure
--------------------------------------------------------------------------------*/
TimerUtility.Timeout._closure=function(arg){
var _scope = arg["scope"] ;
var _arg = arg["args"] ;
return function(){_scope.start.apply(_scope,_arg)};
}
/*--------------------------------------------------------------------------------
Timeoutの開始処理(実行毎に呼び出される)
--------------------------------------------------------------------------------*/
TimerUtility.Timeout.prototype.start
= function(){
if(this._counter<this._count){
this._counter++;
var result=this._ontimer.apply(this,arguments);
this._result.push(result);
if(this._onend){
this._onend(result);
}
this._id=setTimeout(
this.constructor._closure(
{ "scope" : this ,
"args" : arguments }
)
,this._msec
);
}else{
this.stop();
}
}
/*--------------------------------------------------------------------------------
Timeoutの終了処理
--------------------------------------------------------------------------------*/
TimerUtility.Timeout.prototype.stop
= function(){
clearTimeout(this._id);
if(this._onstop){
this._onstop(this._result);
}
}
/*--------------------------------------------------------------------------------
IntervalのClosure
--------------------------------------------------------------------------------*/
TimerUtility.Interval._closure=function(arg){
var _scope = arg["scope"] ;
var _arg = arg["args"] ;
return function(){
if(_scope._counter<_scope._count){
_scope._counter++;
var result=_scope._ontimer.apply(_scope,_arg);
_scope._result.push(result);
if(_scope._onend){
_scope._onend(result);
}
}else{
_scope.stop();
}
};
}
/*--------------------------------------------------------------------------------
Intervalの開始処理(開始時に呼び出される)
--------------------------------------------------------------------------------*/
TimerUtility.Interval.prototype.start
= function(){
this._id=setInterval(
this.constructor._closure(
{ "scope" : this ,
"args" : arguments }
)
,this._msec
);
}
/*--------------------------------------------------------------------------------
Intervalの終了処理
--------------------------------------------------------------------------------*/
TimerUtility.Interval.prototype.stop
= function(){
clearInterval(this._id);
if(this._onstop){
this._onstop(this._result);
}
}
使用例は以下の通り。
<html>
<head>
<script src="TimerUtility.js" type="text/javascript"></script>
<script>
<!--
var to;
var iv;
function rand(str){
var dtm=(new Date()).getTime();
while((new Date()).getTime()<dtm+800){} //時間のかかる処理のダミー
return str+" : "+Math.random();
}
function end(num){
document.getElementById("output").value+=new Date()+" : "+num+"\n";
}
function stop(ary){
alert(ary.join("\n"));
}
function initial(){
initialto();
initialiv();
}
function initialto(){
to=new TimerUtility.Timeout({"ontimer":rand,"onend":end,"onstop":stop,"count":10,"msec":1000});
}
function initialiv(){
iv=new TimerUtility.Interval({"ontimer":rand,"onend":end,"onstop":stop,"count":10,"msec":1000});
}
function startto(){
to.start("timeout");
}
function startiv(){
iv.start("interval");
}
function stopto(){
to.stop();
}
function stopiv(){
iv.stop();
}
function cleardisplay(){
document.getElementById("output").value="";
}
window.onload=initial;
-->
</script>
</head>
<body>
<input type="button" onclick="startto()" value="start timeout" />
<input type="button" onclick="startiv()" value="start interval" /><br />
<input type="button" onclick="stopto()" value="stop timeout" />
<input type="button" onclick="stopiv()" value="stop interval" /><br />
<input type="button" onclick="cleardisplay()" value="clear display" /><br />
<textarea id="output" style="width:90%;height:90%;" readonly="readonly" onclick="this.select();"></textarea>
</body>
</html>
<head>
<script src="TimerUtility.js" type="text/javascript"></script>
<script>
<!--
var to;
var iv;
function rand(str){
var dtm=(new Date()).getTime();
while((new Date()).getTime()<dtm+800){} //時間のかかる処理のダミー
return str+" : "+Math.random();
}
function end(num){
document.getElementById("output").value+=new Date()+" : "+num+"\n";
}
function stop(ary){
alert(ary.join("\n"));
}
function initial(){
initialto();
initialiv();
}
function initialto(){
to=new TimerUtility.Timeout({"ontimer":rand,"onend":end,"onstop":stop,"count":10,"msec":1000});
}
function initialiv(){
iv=new TimerUtility.Interval({"ontimer":rand,"onend":end,"onstop":stop,"count":10,"msec":1000});
}
function startto(){
to.start("timeout");
}
function startiv(){
iv.start("interval");
}
function stopto(){
to.stop();
}
function stopiv(){
iv.stop();
}
function cleardisplay(){
document.getElementById("output").value="";
}
window.onload=initial;
-->
</script>
</head>
<body>
<input type="button" onclick="startto()" value="start timeout" />
<input type="button" onclick="startiv()" value="start interval" /><br />
<input type="button" onclick="stopto()" value="stop timeout" />
<input type="button" onclick="stopiv()" value="stop interval" /><br />
<input type="button" onclick="cleardisplay()" value="clear display" /><br />
<textarea id="output" style="width:90%;height:90%;" readonly="readonly" onclick="this.select();"></textarea>
</body>
</html>
インスタンス化の際の引数は以下の通り。
"ontimer" : 繰り返し行いたい処理。(必須)
"onend" : ontimerに指定された処理の終了時に呼ばれる。ontimerの戻り値が引数となる。(任意)
"onstop" : 指定された回数処理が実行された後、もしくは処理が中断された場合に呼ばれる。それまでに実行された全てのontimerの戻り値(配列)が引数となる。(任意)
"count" : 実行したい回数を指定。Number.POSITIVE_INFINITYを指定すれば無限。(必須)
"msec" : 実行の間隔を指定する。TimerUtility.Timeoutで使用すれば一定時間経過後に、TimerUtility.Intervalで使用すれば一定時間間隔で処理される。(必須)
"onend" : ontimerに指定された処理の終了時に呼ばれる。ontimerの戻り値が引数となる。(任意)
"onstop" : 指定された回数処理が実行された後、もしくは処理が中断された場合に呼ばれる。それまでに実行された全てのontimerの戻り値(配列)が引数となる。(任意)
"count" : 実行したい回数を指定。Number.POSITIVE_INFINITYを指定すれば無限。(必須)
"msec" : 実行の間隔を指定する。TimerUtility.Timeoutで使用すれば一定時間経過後に、TimerUtility.Intervalで使用すれば一定時間間隔で処理される。(必須)
メソッドは次の通り。
start : タイマーを開始する。指定した引数は、ontimerにそのまま引数として設定される。
stop : タイマーを停止する。再度startを実行すると、処理が再開される。
stop : タイマーを停止する。再度startを実行すると、処理が再開される。
以上。
2009/02/04 追記
setTimeoutとsetIntervalの呼び出し方について追記しています。