Skip to content

send と Ajax の送信準備・完了・失敗を読み解く ​

第1版作成 最終更新 (日本時間)
確認バージョン1.5.8.1

$p.send() は操作元とフォームから送信内容を準備し、$p.ajax() は確認・通信・応答反映を担当します。API を呼ぶ $p.apiExec() と違い、この経路は画面操作の命令配列を dispatch に渡します。

「ボタンを押しても送られない」「送信直後に成功と判断してしまう」「失敗したのにイベントが出ない」という問題を、呼び出し順で調べます。

send の引数と入口での中止 ​

呼び出しは $p.send($control, formId, _async, clearMessage) です(入口)。

引数役割
$controlID・data-action・data-method・validate・data-confirm などを持つ操作元
formId明示すればそのフォーム。省略時は操作元の最も近い form
_async省略時は後段で true。syncSend は false を渡す
clearMessageajax のメッセージ消去へ渡す。false なら消去を省く

最初に outsideDialog と no-send を調べ、該当すれば false を返します。outsideDialog は accesskey のある操作元について、表示中のダイアログがあり、その中にいないかを調べます。すべてのダイアログ外操作を禁止する判定ではありません(ダイアログ判定、中止条件)。

送信前に何が起こるか ​

順序処理実装上の境界
1対象フォームを $p.store.$form に入れる明示した formId または closest form
2before_setDatadata はまだ null。false なら中止
3getData、after_setDataバッファを取得するだけ。全 DOM の収集ではない
4URL 作成、メール認証パラメータ、選択タブdata-action を小文字化してフォーム action の _action_ を置換。省略時は現在の URL
5非同期の既定値、ControlId の追加methodType が厳密に get でなければ追加
6validate クラスがあれば検証before_validate → formValidate・valid → after_validate。失敗時は中止
7get 以外なら setMustDataアクションに応じて追加の値を収集
8data-method が定義されていれば ajaxget なら data の引数を null、それ以外はバッファを渡す

根拠は send 全体です。data-method を省略すると、後段の通信へ進みません。data-method="GET" は get との厳密な比較では一致しないので、ここでは小文字を使う前提で読みます。

setMustData は create・bulkupdate・その他で収集範囲が違います。更新操作で全項目を必ず送る関数ではありません(収集条件、送信バッファの詳細)。

図を読み込み中…

ajax に入っても、まだ通信開始ではない ​

$p.ajax(url, methodType, data, $control, _async, clearMessage) は、まず CAPTCHA の準備をします(前処理)。

  • 不要な場合はデータをそのまま使う。
  • reCAPTCHA v2・Turnstile でトークンがなければ、必要な操作を表示して false を返す。
  • reCAPTCHA v3 でトークンがなければ、取得コールバックから $p.ajax を再呼び出しする。最初の呼び出しはその場で終了する。

必要性はメソッドが get 以外か、meta の captcha-type・captcha-site-key があるかで決まります。トークンは data や DOM から確認します(設定とトークン判定、再試行の準備)。CAPTCHA で止まった場合、通常の before_send や通信イベントまで到達しない経路があります。

準備ができたら、before_send の false、操作元の data-confirm による確認、loading、メッセージ消去、ajax_before_send、Token の追加を経て $.ajax へ進みます(送信準備)。

Token の Hidden 要素によるデータ追加とは別に、DOM Ready 時の $.ajaxSetup が同一オリジン向けリクエストへ meta の X-CSRF-TOKEN を付けます(ヘッダー設定)。

戻り値は通信の Promise ではない ​

$p.ajax は内部の jqXHR を返さず、ローカル変数 ret を返します。$p.send はこの戻り値を返す経路があります(ajax の返却、send の引き渡し)。

経路戻り値の意味
通常の非同期通信返却時点の ret は初期値0。後から失敗しても、受け取った0が変わるわけではない
同期通信コールバックで更新した ret を返し得る。成功応答に alert-error の Message があれば -1、通信失敗も -1
before_send・確認などで中止false
CAPTCHA のトークン取得待ち最初の呼び出しは undefined の経路がある
send の data-method なしundefined

await $p.send(...) としても、通常の非同期通信の完了を待つコードにはなりません。同期送信の 0 も、その応答内に alert-error がなかったという判定であり、任意の独自処理の成功保証とは区別します。

after_send は完了イベントではない ​

通常の非同期通信では、登録した done・fail・always より先に ajax_after_send と after_send を呼ぶ位置があります。同期通信では、通信コールバックが戻ってからこれらを呼びます(コールバックの登録と後段)。

成功時は次の順です。

  1. ajax_before_done
  2. setByJson(before_set → 命令実行 → 必要なら UI 再適用 → after_set)
  3. 応答の Message を調べて ret を更新
  4. ajax_after_done
  5. ajax_before_always → ControlId の削除・loaded → ajax_after_always

after_set のイベント引数の ret は dispatch が undefined を渡します。応答内容による ret の判定も、この後です。画面反映後の結果判定を読む場合は ajax_after_done の引数を使います(dispatch の引数、結果判定)。

完了時点の結果を観察する例 ​

以下はブラウザ側のスクリプトです。通常の編集画面へ配置し、既存の検証用レコードで更新を実行します。このコード自体は送信を開始せず、本体の通信完了イベントを記録します。

js
$p.events.ajax_after_done = function (args) {
    console.log('応答反映後', {
        control: args.$control ? args.$control.attr('id') : undefined,
        method: args.methodType,
        ret: args.ret
    });
};
$p.events.ajax_after_always = function (args) {
    console.log('通信の後始末後', {
        ret: args.ret,
        controlIdRemains: !!(args.data && 'ControlId' in args.data)
    });
};

正常な成功応答なら ret は0、alert-error の Message があれば -1です。通常の後始末後には ControlId が削除されています。既存の同名イベントへ追加する場合は 複数処理の登録を使います。CAPTCHA・事前確認などで通信開始前に中止した場合、この完了イベントは呼ばれません。

fail のイベントが出ない経路もある ​

fail では先に ret を -1にし、次の条件を処理します(失敗処理)。

条件失敗時の扱い
abortそこで return。ajax_before_fail・ajax_after_fail を呼ばない
status 0 またはレスポンスヘッダーなしServerConnectionError を出して return。同じく fail 前後イベントを呼ばない
400・403try 内で alert 後に return。ajax_before_fail より前だが finally の ajax_after_fail は呼ぶ
502・503・504ajax_before_fail 後に ServiceUnavailable。finally の ajax_after_fail も呼ぶ
その他サーバー応答のエラーメッセージを表示できなければ InternalServerError。finally で ajax_after_fail

普通に fail が返った場合は、その後の always に進みます。ただし、done 内の dispatch や独自ハンドラで例外が出た場合は、通常の後始末が必ず走ると仮定せず、停止位置をデバッガーで確認してください。応答反映には命令ごとの例外捕捉がありません(dispatch の例外)。

multiUpload は通常の ajax と別の経路 ​

multiUpload は FormData に Token を追加し、contentType: false・processData: false で送ります。アップロード進捗を statusBar へ渡せます(アップロード送信)。

成功時、callback を渡せばその関数が応答を受け取り、なければ応答文字列を JSON.parse して dispatch に渡します。通常の $p.ajax の CAPTCHA 前処理・before_send・ajax_* イベントを呼ぶコードではありません。always では ControlId の削除・loaded・statusBar の非表示を行い、jqXHR は statusBar の setAbort へ渡しますが、この関数自体は返しません(成功・後始末)。

clear と共通タイマーの境界 ​

関数実装と制約
getFormId($control)closest form の ID。フォーム外なら undefined
clear($control)text・checkbox・select の DOM をクリアし、該当バッファを削除。textarea をクリアする分岐はない
setFormChanged($control)not-set-form-changed がなければ $p.formChanged = true
addUrlParameter(url, key, value)? または & とキー・値を連結するだけ。URL エンコードする処理はない
throttle(action, interval)全呼び出しで1つの lastTime を共有する
debounce(action, interval)全呼び出しで1つの timer を共有し、前の予約を消す

根拠は _form.js の前半と後半です。clear の「画面を空にしてバッファを削除」は、「空文字列を登録して保存する」と同じではありません。独自処理用のタイマーを分ける例は API クライアントにあります。

検証範囲と関連ページ ​

送信準備、同期・非同期の返却、成功・失敗イベントの順序と掲載コードは、本体 JavaScript を使い通信を模擬して確認しています。実サーバーへの更新、CAPTCHA サービス、アップロード UI の実機操作は未検証です。

変更履歴

第1版フロント基盤JSのイベント・通信・日時処理を詳しく解説