質問スレPart23の261からの流れが興味深かったのでちょっと実験してみた.
前提
ユーザー JavaScript でできることによれば,.js なスクリプトはすべてのスクリプトの実行の前のとなっていて,一方 ユーザー JavaScript による制御のGreasemokeyスクリプトの節 によれば,.user.js にしたスクリプトは DOMContentLoade
以降 load
前になっているので,以下の順序で実行されることが予想される.
- *.js
- DOMContentLoaded
- *.user.js
- onload
.js で登録した DOMContentLoaded
と 文書内でインラインで登録した DOMContentLoaed
との関係や,.js で登録した onload
と body.onload
と*.user.js で登録した onload
との関係などは特に規定されていない.また DOMContentLoaded
と body.onload
の間にはページ内の各画像類の onload
が発生するはずだがその順序も特に規定されてない.さらに Extension との関係もイマイチ不明.
実験
Opera 11.01.1169 で
- HTML
- Script
- UserJS
- Extension
という構成にして実験してみたところ Dragonfly のエラータブで以下の出力が得られた.
console.log 1 in extension injected.js
console.log 2 in test.js
console.log 8 in extension injected.js BeforeScript listener; window.addEventListener('DOMContentLoaded', function(){ console.log( 'in html DOMContentLoaded listener' ); }, false );
console.log 10 in test.js BeforeScript listener; window.addEventListener('DOMContentLoaded', function(){ console.log( 'in html DOMContentLoaded listener' ); }, false );
console.log 11 in extension injected.js AfterScript listener; window.addEventListener('DOMContentLoaded', function(){ console.log( 'in html DOMContentLoaded listener' ); }, false );
console.log 13 in test.js AfterScript listener; window.addEventListener('DOMContentLoaded', function(){ console.log( 'in html DOMContentLoaded listener' ); }, false );
console.log 4 in extension injected.js BeforeExternalScript listener; <http://ashula.info/lab/opera/inhead.js>
console.log 6 in test.js BeforeExternalScript listener; <http://ashula.info/lab/opera/inhead.js>
console.log 8 in extension injected.js BeforeScript listener; console.log( 'in inhead.js via script.src' );
console.log 10 in test.js BeforeScript listener; console.log( 'in inhead.js via script.src' );
console.log 1 in inhead.js via script.src
console.log 11 in extension injected.js AfterScript listener; console.log( 'in inhead.js via script.src' );
console.log 13 in test.js AfterScript listener; console.log( 'in inhead.js via script.src' );
console.log 8 in extension injected.js BeforeScript listener; console.log('in html before image');
console.log 10 in test.js BeforeScript listener; console.log('in html before image');
console.log 1 in html before image
console.log 11 in extension injected.js AfterScript listener; console.log('in html before image');
console.log 13 in test.js AfterScript listener; console.log('in html before image');
console.log 8 in extension injected.js BeforeScript listener; console.log('in html after image');
console.log 10 in test.js BeforeScript listener; console.log('in html after image');
console.log 1 in html after image
console.log 11 in extension injected.js AfterScript listener; console.log('in html after image');
console.log 13 in test.js AfterScript listener; console.log('in html after image');
console.log 4 in extension injected.js BeforeExternalScript listener; <http://ashula.info/lab/opera/inbody.js>
console.log 6 in test.js BeforeExternalScript listener; <http://ashula.info/lab/opera/inbody.js>
console.log 1 in html img.onload
console.log 8 in extension injected.js BeforeScript listener; console.log( 'in inbody.js via script.src' );
console.log 10 in test.js BeforeScript listener; console.log( 'in inbody.js via script.src' );
console.log 1 in inbody.js via script.src
console.log 11 in extension injected.js AfterScript listener; console.log( 'in inbody.js via script.src' );
console.log 13 in test.js AfterScript listener; console.log( 'in inbody.js via script.src' );
console.log 17 in test.js DOMContentLoaded listener;
console.log 15 in extension injected.js DOMContentLoaded listener;
console.log 1 in html DOMContentLoaded listener
console.log 2 in test.user.js
console.log 19 in extension injected.js load listener;
console.log 21 in test.js load listener;
console.log 1 in html body.onload
console.log 4 in test.user.js window.load listener
整理すると
- Extension の injected script
- *.js な UserJS
- BeforeScript
- Extension, UserJS の順
- インライン script
- AfterScript
- Extension, UserJS の順
- BeforeExternalScript
- Extension, UserJS の順
- BeforeScript
- Extension, UserJS の順
- script src=“” なスクリプト
- AfterScript
- Extension, UserJS の順
- (img.onload)
- DOMContentLoaded
- Extension, UserJS, インライン の順
- *.user.js な UserJS
- load
- Extension
- *.js な UserJS
- body.onload
- *.user.js な UserJS
となった.BeforeScript
などの window.opera
固有のイベントは Extension,*.js と登録された順に発火している.DOMContentLoaded
も Extension,*.js,インラインとなった.load
に関しては,Extension,*.js,インライン,*.user.js 登録された順となった
load
イベントの順序で body.onload
が *.user.js より先に実行されているのは DOMContentLoaded
発火時すでに, body.onload
が load
に登録されているためと考えられる.
img.onload
が DOMContentLoaded
より先に発火しているが,外部のリソースを読み込む script 要素が直後にあるためと考えられる.
まとめ
Extension と 2 種の UserJS の実行タイミングを調査し Extension,*.js,*.user.js となっているのを確認した.
BeforefScript, BeforeExternalScript, AfterScript
の window.opera
固有イベントは や DOMContentLoaded
は EventListener が登録された順に実行されている事がわかった.
*.user.js で onload に登録すれば body.onload
より後に実行できるので本当に最後に実行出来る事もわかった.
追加実験
この結果はDragonfly 起動時限定., opera.postError なら確かめられるのでは という指摘を頂いたので,ちょっと実験してみた.
console.log を使っていたところをすべて opera.postError に書き換えて,出力の最初に Date.now() を入れるようにし,Exstension の Injected Script に jQuery 1.4.4 (mini) を追記してみたところ,*.js な UserJS のほうが先に実行される様になった.Date.now() の出力値は同じだったが,イベントハンドラの実行順から extension のほうが後だと考えられる.