JSONP-SEについて気になったこと

川崎有亮さんの静的JSONPファイルなのにコールバック関数名を指定できるJavaScriptのエントリに、

凄いけどレスポンスが帰ってくるタイミングしだいではうまく行かないような

こんなはてブコメをつけたんですが、時間がたったら自信がなくなってきたので検証してみました。


JSONP-SEではロードされたJavaScriptが自分自身に対応するsrcipt要素の
src属性から「callback=何某」をぶっこ抜きます。
ロードされたjavaScriptに対応するscript要素が、
必ず、その時点で一番最後のscript要素であるという前提になっていて、
この前提が崩れると適切なコールバック関数名を取得できません。


なので、処理としては、その時点で一番最後のscript要素のsrc属性をグローバル変数に格納するだけで、
レスポンスが帰ってくる時間だけが違う二つのjsファイル(相当のもの)を使って、
検証してみます。

使用するjsファイル(および相当のもの)

1000ms強待ってからレスポンスが帰ってくるjsファイルとして振舞うA.jsp

<%@page pageEncoding="UTF-8" contentType="application/x-javascript; charset=UTF-8" %>
<% 
try {
	Thread.sleep(1000);
} catch (InterruptedException e) {}
 %>
(function(){
	var list = document.getElementsByTagName('script');
	var src = list[list.length-1].src;
	a = src;
})()

普通のjsファイルであるB.js

(function(){
	var list = document.getElementsByTagName('script');
	var src = list[list.length-1].src;
	b = src;
})()

検証1:HTML中にscriptタグを書く場合

<html>
<head>
</head>
<body>
<script type="text/javascript" src="http://localhost:8080/A.jsp"></script>
<script type="text/javascript" src="http://localhost:8080/B.js"></script>
<script type="text/javascript">
window.onload = function(){
	var div = document.createElement('div');
	div.innerHTML = 'a:' + a + '<br>b:' + b; 
	document.body.appendChild(div);
}
</script>
</body>
</html>

結果はIEFirefoxOperaで以下のようになったので問題ないです。

a:http://localhost:8080/A.jsp
b:http://localhost:8080/B.js

一つ目のscriptタグでレスポンスが帰ってくるまで待っている間は完全にストップしてます。

検証2:DOMでscript要素を生成する場合

<html>
<head>
</head>
<body>
<script type="text/javascript">
window.onload = function(){
	var scriptA = document.createElement('script');
	scriptA.charset = 'utf-8';
	scriptA.type = 'text/javascript';
	scriptA.src = 'http://localhost:8080/A.jsp';
	var scriptB = document.createElement('script');
	scriptB.charset = 'utf-8';
	scriptB.type = 'text/javascript';
	scriptB.src = 'http://localhost:8080/B.js';
	document.lastChild.appendChild(scriptA);
	document.lastChild.appendChild(scriptB);

	setTimeout(function(){
		var div = document.createElement('div');
		div.innerHTML = 'a:' + a + '<br>b:' + b; 
		document.body.appendChild(div);
	},2000);
}
</script>
</body>
</html>

結果はIEFirefoxでは以下の通り

a:http://localhost:8080/B.js
b:http://localhost:8080/B.js

Operaでは以下の通り

a:http://localhost:8080/A.jsp
b:http://localhost:8080/B.js


なので、script要素を生成する場合は前提が崩れてしまっているので、
JSONP-SEが正常に動く保障がありません。
script要素を生成して動的にライブラリを読み込んでから
実際にライブラリが使えるようになるまでにラグがあるというアレと一緒なのでしょう。
Operaの場合の結果が予想外だったので引き続き調査してみようと思います。