barba.js の非同期通信を Web Worker に置き換える
barba.js はウェブサイトのページ動的遷移 (Pjax) を実現するにあたり、かなり定番といえるライブラリと言えます。
この barba.js にはページを事前取得する prefetch が実装されているのですが、リンクの clickではなくmouseover / touchstart するだけでトリガーされる設計となっており、裏側でかなり頻繁に非同期通信を実行しています。
htmlのfetch程度なのでそれほどリソースは喰わないだろうと思いつつも、こうした設計なのであればそれなりに負荷はあるのだろうなと思い、この部分を Web Worker に任すことができないか。という思いつきから生まれたのが前回の記事に書いた ajaxWorker だったりします。
* prefetch はオプションでオフにすることもできます。
しかし barba.js には様々な API が用意されているとはいえ、非同期通信部分の処理を拡張することを想定した都合の良い設計にはなっていません。
試行錯誤の結果として成功はしたのでメモとして残しておきますが、ちょっと強引な手法にはなります。
非同期通信の処理をしているコードを特定
GitHub で公開されている barba.js のソースファイル群から JavaScript で非同期通信を実行する XMLHttpRequest の含まれるコードを検索したところ、1ファイルしかなくあっさりと特定できました。
問題は、実行ファイルのこの部分に自身の書くスクリプトから変更を加えることができるか。なのですがドキュメントに記載はないものの、アクセス可能かつリライト可能な変数として barba.request にこの処理が格納されていることが分かりました。
barba.request の処理を ajaxWorker で上書き
上記 request.ts で行っている非同期通信を ajaxWorker に置き換え、通信成功時とエラー時の処理を反映させたものが以下となります。これを barba.init() の実行前に記述すればOK。
思いっきり上書きしてしまっていますが、本体のソースに直接手を加えているわけではないので動作に不具合が出れば削除すればすぐに元の状態に戻せます。
barba.request = function (url, ttl, requestError) {
return new Promise(function (resolve, reject) {
ajaxWorker({
url: url,
dataType: 'text',
headers: {
'Accept': 'text/html, application/xhtml+xml, application/xml',
'x-barba': 'yes'
},
timeout: ttl,
success: function (_data) {
// console.log('success', _data);
resolve(_data);
},
error: function (_status, _statusText, _message) {
// console.log('error', _status, _statusText, _message);
const res = {
status: _status,
statusText: _statusText
};
requestError(url, res);
reject(res);
}
});
});
};
barba.init({
...
});
その後実際に稼働させてみたところ、問題なく動作したため現在制作しているウェブサイトにも投入してみています。大きく速度が向上したとか負荷が減ったという体感レベルの変化はいまのところはありませんが、ちょっと嬉しい。
barba.js がバージョンアップして barba.request の処理が変更となった場合には動作しなくなる可能性はありますので、アップデートする際には気をつけてください(マイナーバージョンアップ程度でこの部分が大きく変わることはないと思いますが)。