Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

jQuery 3での変更点 ~ Promises/A+互換となったDeferred機能を中心に

jQuery 3で何が変わったのか? 後編

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2016/08/18 14:00

 今年2016年6月9日、ついに正式版がリリースされた jQuery 3。メジャーバージョンアップしたjQuery 3では、従来のバージョンから、いったい何が変わったのかを2回に分けて解説します。

目次

はじめに

 今回は、Ajax、Deferred機能などを中心に紹介しましょう。

 また、先日7月7日に、jQuery 3.1.0がリリースされましたので、そちらの変更点も併せてお伝えします。

対象読者

  • Webアプリケーション開発に興味があり、jQueryを知っている方

Deferred機能

 $.Deferredは、jQuery 1.5から導入された非同期処理のための標準モジュールです。ここでは、少し$.Deferredの基本的なところをおさらいしてから、jQuery 3での変更点を解説することにしましょう。

 なお、jQuery 3での$.Deferredでは、破壊的な変更が3つあり、そのうち2つには新機能が含まれています。

$.Deferredとは

 Deferredとは、英語で、遅延、据え置きされた、などの意味 で、$.Deferredは、Promisesという概念を元に設計されたオブジェクトです。Promises(約束)の概念は、身近な例でいうと、フードコードなどで使われる呼び出しベルのようなものです。非同期処理を待つ(ブロッキング)代わりに、将来のある時点の応答を返すオブジェクト(Promises)を使ってノンブロッキングに処理を行う、という考え方です。$.Deferredでは、このPromiseオブジェクトを内包しています。

 Promiseオブジェクトは、初期状態ではpendingという状態になっています。通常、非同期処理を実行後に、resolveメソッドかrejectメソッドで、Deferrdの状態を確定させます。resolveメソッドは、正常終了、rejectメソッドは異常終了した状態を表します。正常終了時には、doneメソッドで設定したコールバック、異常終了時には、failメソッドで設定したコールバックが実行されます。

Deferredと非同期処理の関係
Deferredと非同期処理の関係

 また、thenメソッドを使えば、done、failメソッドを同時に定義できる上、新たなDeferrdオブジェクトを返します。したがってメソッドチェーンが使え、非同期処理を順番に処理したい場合でも、コールバックを多重に定義することなく、スマートに記述することができます。

thenメソッドでの連続処理
thenメソッドでの連続処理

Promises/A+互換

 最初の変更点は、$.Deferredが非同期処理の標準仕様であるPromises/A+に準拠したことです。jQueryの$.Deferredでは、Promises/A+の仕様と一部異なっていました。

1.Resolution(終了処理)

 Deferredオブジェクトの、resolve、reject、notifyメソッドは、 コンテキストとしてundefinedを返すようになりました。従来は、呼び出し元のDeferredオブジェクトが内包するPromiseオブジェクトが返されていました。たとえば、次のサンプルの場合、以前は、trueとなっていました。

var defer = $.Deferred();
setTimeout(function() {
     defer.resolve();
}, 1000);

// 1秒後に実行
defer.then(function(){
    console.log(this == defer.promise()); // false(従来はtrue)
});

 なお、明示的に コンテキストを渡したい場合には、resolveWith、rejectWith、notifyWithメソッドを利用します。

var defer = $.Deferred();
setTimeout(function() {
   defer.resolveWith($("#test"));
 }, 1000);

// 1秒後に実行
defer.then(function(){
     console.log(this); // thisは、$("#test")
 });

2.コールバックの終了処理

 2つめは、Deferredオブジェクトのthenメソッドの大きな変更です。

 thenメソッドで指定したコールバック内で何らかの例外が発生すると、defferdオブジェクトの状態をreject(異常終了)に移行します。jQuery 3では、この例外を補足するためのcatchメソッドが追加されました。メソッドチェーンの最後に、catchメソッドを追加することが、 強く推奨されています。

 従来では、thenメソッドのコールバックで例外が発生した場合、コード実行が中断されて、defferdオブジェクトの外側に伝播されていました。

var defer = $.Deferred();
setTimeout(function() {
   defer.resolve();
}, 1000);
defer.then(function(){
    sample(); // 未定義メソッドの呼び出し
 }).catch(function(){
    console.log("error"); // 例外が補足されて、このコードが実行される。
});

 promises/A+の仕様では、promiseオブジェクトは常に1つの値として最後まで遷移し、コールバックでは、コンテキストなしで実行することになっています。ところが、jQueryのDeferredでは、複数の値を扱うことも可能です。コンテキストや複数の値を受け取りたい場合は、従来のdoneやfailメソッドを使ってください。

 なお、thenメソッドの実行は、document-readyと同様、非同期になりました。

// promises/A+準拠ではないthenメソッドの使い方
$.ajax("test.php").then(
    function( data, textStatus, jqXHR ) {
        console.log("OK");
}, function( jqXHR, textStatus, errorThrown ) { // エラー時の処理
        console.log(errorThrown);
});

// 従来と同じ挙動のコード
$.ajax("test.php").done(
    function( data, textStatus, jqXHR ) {
        console.log("OK");
}).error( function( jqXHR, textStatus, errorThrown ) { // エラー時の処理
        console.log(errorThrown);
});

3.後方互換性

 Deferredオブジェクトのdone、fail、pipeメソッドは、後方互換性のために従来と同じ挙動になっており、Promises/A+に準拠していません。もし、従来のコードのまま利用したい場合は、then、catchメソッドの代わりに、doneやfailなどのメソッドを使います。

$.whenメソッドの引数

 $.whenメソッドの引数には、thenメソッドを持つ、Promise仕様に準拠した、いわゆるthenableオブジェクトならば何でも設定可能です。ECMAScript 6仕様のPromiseオブジェクトなども利用できます。

 また、引数が2つ以上の場合と、引数がないか1つのときで、挙動を区別するようになりました。引数が2つ以上のときは、Promise.allメソッドと同じようにふるまい、引数がないか1つの場合は、Promise.resolveメソッドと同様になります。いずれも、戻り値は、新たに生成されたDeferredオブジェクトとなります。

var defer1 = $.Deferred();
setTimeout(function() {
    defer1.resolve();
}, 1000);

var defer2 = $.Deferred();
setTimeout(function() {
    defer2.resolve();
}, 1500);

// defer1, defer2の処理を待つ
$.when(defer1, defer2).done(function(){
});
// Promise.allメソッドと同じ
Promise.all([defer1, defer2]).then(function() {
});

// 引数が1つのとき、Promise.resolveと同じ挙動
$.when(defer1).done(function(){
});
// Promise.resolveと同じ
Promise.resolve(defer1).then(function() {
});

$.whenメソッドの進捗通知を削除

 jQuery 3では、$.whenメソッドの引数のDeferredオブジェクトから、戻り値のDeferredオブジェクトに対する進捗の通知は削除されました。Promises/A+の仕様には、進捗メッセージについての規定はありません。また従来より、この機能についてはドキュメント化されていませんでした。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • WINGSプロジェクト 高江 賢(タカエ ケン)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XMLD...

バックナンバー

連載:jQuery 3で何が変わったのか?
All contents copyright © 2005-2018 Shoeisha Co., Ltd. All rights reserved. ver.1.5