ブラウザの API クライアントと非同期処理を読み解く
$p.apiGet() などの関数は、API に JSON を POST し、jqXHR を返すラッパーです。通常の画面送信用 $p.ajax() のように、応答を dispatch へ渡したり、フォームの送信バッファを自動収集したりはしません。
API の対応表は API ラッパー、このページでは実装と結果の受け取り方を扱います。
apiUrl とラッパーの担当
apiUrl(id, action, controller) は #ApplicationPath と引数を連結します(URL 生成)。
| 指定 | 作るパスの形 |
|---|---|
| controller なし | api/items/id/action |
| controller と真と評価される id | api/controller/id/action |
| controller あり、id が偽と評価される値 | api/controller/action |
URL エンコードや引数の妥当性検証をする処理ではありません。apiGet などは args.id を読み、URL を作って apiExec へ渡します。apiExec の args 省略対応は、apiGet の args 省略対応を意味しません。 apiGet() はその前に args.id を読むため、引数が必要です(レコードのラッパー、共通実行)。
apiExec がすること・しないこと
| 処理 | 実装 |
|---|---|
| data の既定値 | args.data が undefined なら空オブジェクト |
| Token | Hidden の #Token が1件なら data.Token へ追加。元のオブジェクトも変わる |
| 本文 | JSON.stringify(data) |
| HTTP メソッド | post。apiGet も HTTP GET ではない |
| 応答の型 | dataType は json |
| Content-Type | URL が api/ に一致する条件なら application/json |
| 結果 | $.ajax の jqXHR を返し、done・fail・always を登録 |
根拠は apiExecです。dataType は応答の解析指定であり、リクエストの Content-Type とは別です。この経路は $p.ajax を呼ばないため、before_send・CAPTCHA 前処理・dispatch・フォームの ControlId 削除なども呼びません。一方、$.ajaxSetup の共通設定は $.ajax に適用されます(画面送信との比較、画面送信本体)。
読み取り結果を受け取る例
以下はブラウザ側のスクリプトです。閲覧できる既存レコードの編集画面で、ブラウザコンソールから実行します。応答の形を決め打ちせず、API から受け取った JSON を確認する読み取り例です。
(function () {
const id = $p.id();
if (!Number.isFinite(id) || id <= 0) {
console.warn('読み取るレコード ID がありません。');
return;
}
$p.apiGet({
id: id,
data: {},
done: function (response) {
console.log('API の応答', response);
},
fail: function (xhr, status, error) {
console.warn('API の通信失敗', xhr.status, status, error);
},
always: function () {
console.log('API の通信終了');
}
});
})();done は jqXHR の通信成功に対応します。保存・業務処理の成功判定や、返却データの項目確認は API の応答に合わせて別に行います。返却形式は ApiVersion の決まり方も確認してください。
Promise として待つ例
同じ読み取りを async 関数で待つ場合は、返された jqXHR を await します。通常の $p.send() の即時の数値とは違います。
(async function () {
const id = $p.id();
if (!Number.isFinite(id) || id <= 0) return;
try {
const response = await $p.apiGet({ id: id, data: {} });
console.log('API の応答', response);
} catch (xhr) {
console.warn('API の通信失敗', xhr.status);
}
})();async の指定はグローバル設定を変える
args.async が undefined でなければ、apiExec は $.ajaxSetup({ async: args.async }) を実行します。リクエスト個別の設定に async を入れたり、呼び出し後に設定を戻したりする実装ではありません(設定変更)。
例えば { async: false } を渡すと、その後に明示的な指定をしない他の jQuery Ajax にも影響する共通設定が残ります。読み取り例は async を渡さず、この変更を行いません。$p.ajax はリクエスト個別に async を指定するため、この点でも API ラッパーと違います(個別指定)。
一括削除は通常の apiExec とも違う
apiBulkDelete は apiBulkDeleteExec へ進みます。ここでは args.data.GridCheck を読み、真なら一覧の選択状態から All と Selected を data へ追加します(一括削除)。
- GridCheckAll が真なら、GridUnCheckedItems を除外側の ID 一覧として使う。
- それ以外は GridCheckedItems を選択側の ID 一覧として使う。
- data を省略した場合に備えるコードより先に args.data.GridCheck を読むため、data オブジェクトを用意する必要がある。
- この経路には、通常の apiExec の Content-Type 設定と cache の明示がない。
選択状態のキーが必要な経路を、任意の画面から呼べる削除関数として扱わず、一覧の状態と要求するデータを確認します。このページの実行サンプルには削除処理を含めません。
独立したデバウンスを持つ例
入力から API 検索へつなぐ場合、本体の $p.debounce は全呼び出しでタイマーを共有し、自動ポストバックの Enter 送信にも使われます。自作処理には別のタイマーを用意します(共通タイマー、本体での利用)。
次はブラウザコンソール用の、独立した予約関数の例です。通信はせず、最後の呼び出しだけを実行する仕組みを試します。
(function () {
let timer;
const schedule = function (action, delay) {
clearTimeout(timer);
timer = setTimeout(action, delay);
};
schedule(function () { console.log('最初'); }, 100);
schedule(function () { console.log('最後'); }, 100);
})();100 ms 後に 最後 だけを出します。API 検索へ応用するときは、通信の応答順も別に管理します。タイマーで開始回数を減らすことと、先に開始した通信の結果を後から採用しないことは別の制御です。
検証範囲と関連ページ
URL・要求設定・データの変更・jqXHR の受け取りと掲載コードは、本体 JavaScript と模擬通信で確認しています。実サーバーでの権限・API 応答・保存処理は未検証です。