The Document of Aska

3-2. Correct

通常のWebページの生存期間はせいぜい数分ですが、One Page Applicationでは数日以上開いたままという事も珍しくありません。

更に、ソーシャル連携等で複数人による操作が可能な場合ガンガン画面とサーバーでデータがずれていきます。

そんな過酷な環境でも安心して使用できる様にするには、細やかな同期処理が必要です。

  1. 定期的に同期する
  2. 操作対象が既に存在しない、権限がない等不整合が検出された場合に同期する

定期的に同期する

最も原始的な方法は location.reload() ですが、操作途中の内容が消えてしまう最悪な手段です。

エレガントに同期を回復するにはboot用APIから情報を再取得し変更がある場合、メモリ上のデータとDOMを一致させます。

画面上の状態、つまり選択しているリストやタスクは極力元に戻す等のケアが使用感を向上させます。

この時利用するのが clear, setup の2つのカスタムイベントです、 setupは素のHTMLにWebAPIから取得したデータをはめる処理を行うイベント、 clearは素のHTMLに戻すイベントです、同期状態を回復したい場合 app.util.reload() でclearとsetupイベントを発火します。

操作対象が既に存在しない、権限がない等不整合が検出された場合に同期する

Ajaxでステータスコード403又は404が帰ってきた場合に、画面上とサーバー間でデータの不整合が発生しています、エラーメッセージを表示している隙に素早く前項のreloadを行いましょう。

この時、削除された、又は権限を外されたリストが画面から消えたりします。

app.ajax = function(option){
    if ("data" in option && "type" in option && option.type.toLowerCase() === 'post') {
        if (typeof option.data === 'object') {
            option.data[app.CSRF_TOKEN_NAME] = app.env.token;
        } else {
            option.data = option.data + '&' + app.CSRF_TOKEN_NAME + '=' + app.env.token;
        }
    }
    return $.ajax(option)
    .fail(function(jqXHR, textStatus, errorThrown){

        // Offline
        if (!jqXHR.status) {
            app.fireEvent('alert', 'offline');
            app.state.offline = true;
        }

        // Unauthorized
        else if (jqXHR.status === 401) {
            if (option.setup) {
                app.dom.show($('#signin'));
            } else {
                app.fireEvent('alert', jqXHR.status);
                setTimeout(function(){
                    location.href = '/';
                }, 3000);
            }
        }

        // Collision
        else if (jqXHR.status === 403 || jqXHR.status === 404) {
            app.fireEvent('alert', jqXHR.status);
            setTimeout(function(){
                app.fireEvent('reload');
            }, 3000);
        }

        // Internal Server Error
        else if (jqXHR.status >= 500) {
            app.fireEvent('alert', jqXHR.status);
        }
    });
}