LoginSignup
1
2

More than 1 year has passed since last update.

Ajax通信が全て完了したことをトリガーにして処理を呼び出したい

Last updated at Posted at 2022-12-21

背景

Laravelのフラッシュデータを使うと、そのリクエスト間だけセッションにデータを保持できますが
これをAjax通信などで利用すると、他のXHRが干渉してフラッシュデータが破棄されてしまう可能性があります。

回避策としてLaravelはreflash()keep()という機能を提供していますが、制約的に実現が難しかったので
「Ajax通信が全て終わってからリクエストできるようにすればいいんじゃないか?」と思い調べた結果を共有します。

どうやるか

((open) => {
    const openedXhr = [];
    XMLHttpRequest.prototype.open = function (method, url, async, user, pass) {
        this.addEventListener('readystatechange', () => {
            switch (this.readyState) {
                case 1: // OPENED
                    openedXhr.push(this);
                    break;
                case 4: // DONE
                    const i = openedXhr.indexOf(this);
                    if (i > -1)
                        openedXhr.splice(i, 1);
                    if (!openedXhr.length)
                        // フラッシュデータを使うAPIを叩く
                        break;
            }
        });
        open.call(this, method, url, async, user, pass);
    };
})(XMLHttpRequest.prototype.open);

Ajaxで使われるXMLHttpRequest.prototype.openをインターセプトしてreadystatechangeを監視します。
ステータスが全てDONEになったら全てのXHRが完了していることを保証できるため、フラッシュデータを使う処理を実行します。
今回のようなユースケースに限らず、Ajax通信が全て完了したことをトリガーにした処理を実装したい時に使えると思います。

なおこの即時関数が呼び出される前に実行されたXHRは当然制御できませんが、ユーザーが内部APIをコールするようなアクションを制御したいユースケースであればある程度は制御可能かと思います。

他の懸念点としては

  • 例えば1件目のXHRが2件目を監視する前にDONEになるとAPIが呼ばれてしまう
  • XHRの件数が多いとユーザーを待たせる可能性もある
  • 一定間隔でAjax通信しているようなケースだと更に制御が必要になったりする

などいろいろあります(参考程度にお読みいただければ幸いです)。

備考

この記事は以前Stack Overflowで見かけた内容を元にしているのですが、記事を見失ったためメモ代わりに投稿しました...

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2