JavaScriptでsleep

薀蓄

 JavaScriptにsleep処理ができないか,その手の質問を良く見かけます。JavaScriptだけで所謂sleep処理はできないのですが,ビジーリードを用いるかJavaScript以外の仕組みを用いれば実現できなくはありません。但し,同期処理や非同期処理,タイマやインターバルを使えば大抵の場合実際に実現したい機能は実装できるはずで,sleep機能を使いたいと思った場合には,先にそちらを検討されることをお勧めします。

サンプル







ソース

sleep.pl
#! /usr/local/bin/perl

use	CGI;

my	$cgi = new CGI();
my	$wait = $cgi->param('wait');
$wait =~ s/\D+//g;
$wait /= 1000;
$wait = 10 if ($wait > 10);
sleep($wait);

print "Content-type: text/plain; charset=Shift_JIS\n\n";
print "${wait}.";

1;

JavaScriptSleep.java
function createHttpRequest() {
	var	httpRequest = null;
	if (window.XMLHttpRequest){
		httpRequest = new XMLHttpRequest();
	} else if (window.ActiveXObject){
		try {
			httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e2) {
			}
		}
	}
	return httpRequest;
}
function sleep_server(wait) {
	var	httpRequest = createHttpRequest();
	try {
		httpRequest.open('POST','http://'+doument.domain+'/%7elunlumo/cgi-bin/sample/sleep.pl',false);
		httpRequest.setRequestHeader("content-type", "application/x-www-form-urlencoded");
		httpRequest.send("wait="+escape(wait));
	} catch(e) {
		alert("request failed.(" + e + ")");
	}
}

sleep.js
function createHttpRequest() {
	var	httpRequest = null;
	if (window.XMLHttpRequest){
		httpRequest = new XMLHttpRequest();
	} else if (window.ActiveXObject){
		try {
			httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e2) {
			}
		}
	}
	return httpRequest;
}
function sleep_busy(wait) {
	var start = (new Date()).getTime();
	while (true) {
		if ((new Date()).getTime() >= start + wait * 1) break;
	}
}
function sleep_server(wait) {
	var	httpRequest = createHttpRequest();
	try {
		httpRequest.open('POST','http://'+document.domain+'/~lunlumo/cgi-bin/sleep.pl',false);
		httpRequest.setRequestHeader("content-type", "application/x-www-form-urlencoded");
		httpRequest.send("wait="+escape(wait));
	} catch(e) {
		alert("request failed.(" + e + ")");
	}
}
function sleep_applet(wait) {
	document.applets["JavaScriptSleep"].sleep_applet(wait);
}
function sleep_test(sleep_type) {
	var	wait = document.getElementById("wait").value;
	switch(sleep_type) {
		case	1:	sleep_busy(wait); break;
		case	2:	sleep_server(wait); break;
		case	3:	sleep_applet(wait); break;
		default: break;
	}
	alert("wakeup");
}

解説

ビジーリード

 詳しく解説するまでもないかと思いますが,呼び出し時の時刻を取得し,現在時刻と処理開始時時刻の差が指定された時間を越えるまでひたすらループします。
sleep_busy
function sleep_busy(wait) {
	var start = (new Date()).getTime();
	while (true) {
		if ((new Date()).getTime() >= start + wait * 1) break;
	}
}
 外部リソースとのタイミングを取る場合には同期もしくは非同期処理で対応できるので,使うとすればクライアント側の待ちになるかと思いますが,この場合もCPU負荷が高いのでインターバルを使う方が現実的でしょう。

サーバサイド

 サーバサイドにsleep処理を実装し,その応答を同期処理で待つ事でsleepを実現します。今回のサンプルでは,サーバ側にはCGIを用意しました。(*1)
sleep.pl
#! /usr/local/bin/perl

use	CGI;

my	$cgi = new CGI();
my	$wait = $cgi->param('wait');
$wait =~ s/\D+//g;
$wait /= 1000;
$wait = 10 if ($wait > 10);
sleep($wait);

print "Content-type: text/plain; charset=Shift_JIS\n\n";
print "${wait}.";

1;

sleep_server
function createHttpRequest() {
	var	httpRequest = null;
	if (window.XMLHttpRequest){
		httpRequest = new XMLHttpRequest();
	} else if (window.ActiveXObject){
		try {
			httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e2) {
			}
		}
	}
	return httpRequest;
}
function sleep_server(wait) {
	var	httpRequest = createHttpRequest();
	try {
		httpRequest.open('POST','http://'+doument.domain+'/%7elunlumo/cgi-bin/sample/sleep.pl',false);
		httpRequest.setRequestHeader("content-type", "application/x-www-form-urlencoded");
		httpRequest.send("wait="+escape(wait));
	} catch(e) {
		alert("request failed.(" + e + ")");
	}
}
*1) サンプルとしてアップロードしたスクリプトでは,サーバの負荷を考慮してsleep処理は行わず即時に応答を返しています。

JavaApplet

 ページに貼り付けたJavaAppletのメソッドを呼び出してsleepを実現します。
JavaScriptSleep.java
package	jp.lunlumo.javascript_sleep;

import	java.awt.BorderLayout;
import	java.awt.Container;
import	javax.swing.JApplet;
import	javax.swing.JTextField;

public class JavaScriptSleep extends JApplet {
	JTextField	message;
	
	public void init(){
		Container	contentPane = getContentPane();
		message = new JTextField(10);
		setLayout(new BorderLayout());
		add(BorderLayout.CENTER,message);
	}
	
	public void sleep_applet(long wait) {
		message.setText("wait "+wait+"...");
		repaint();
		try {
			Thread.sleep(wait);
		} catch(Exception ex) {
		}
		message.setText("");
		repaint();
	}
}

sleep_applet
function sleep_applet(wait) {
	document.applets["JavaScriptSleep"].sleep_applet(wait);
}
 JavaAppletを使うこの方法はクライアント側の負荷も低いので,どうしてもsleepを使いたい場合にはお勧めです。sleepを使わなければ実現できない処理はおそらく無いとは思いますが。

リンク

お薦め