2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

$.Deferred() について理解してみる

Posted at

■概要

以下不明点を解消したいので調べました

  • JavaScriptのコードで$.Deferred()って出てくるけどこれなんだっけ
  • then()ってメソッドがたくさん連なっているがなにを表しているのか
  • resolve()promise()reject()とはなんだろう
  • なんとなく非同期処理関係っぽいけど...。

■調べたこと

〇まずは、Deferredの意味

defer(延期する)の過去形。延期された、先送りされた。

$.Deferred() 概要

参照:https://api.jquery.com/jQuery.Deferred/

  • $.Deferred()を省略せずに書くとjQuery.Deferred()
  • jQueryで用意されている関数(jQuery 1.5 で導入された)
  • ファクトリ関数。以下のメソッドを持つオブジェクトを返してくれる
    • 複数のコールバック関数をキューに登録する
    • 登録したコールバック関数を呼び出す
    • 同期または非同期関数の成功または失敗の状態を中継する

■ここまでの理解

$.Deferred()は、オブジェクトを用意する関数
・そのオブジェクトは、登録した「コールバック関数」の実施タイミングや順番を操るメソッドをもつ

■では、具体的な使い方は?

$.Deferred()が返してくれるオブジェクトのメソッドについて

参照:https://api.jquery.com/category/deferred-object/

  • 以下のようなメソッドがあるようだ(※非推奨 になっているものは省きました)
    • jQuery.Deferred()
      Deferredオブジェクトを返すファクトリ関数

    • jQuery.when()
      0 個以上の Thenable objects (通常は非同期の Deferred オブジェクト) に基づいてコールバック関数を実行する方法を返す

    • deferred.always()
      引数の関数を、Deferredオブジェクトが「解決」か「拒否」されたときに呼び出す関数に追加する

    • deferred.catch()
      引数の関数を、Deferredオブジェクトが「拒否」されたときに呼び出す関数に追加する

    • deferred.done()
      引数の関数を、Deferredオブジェクトが「解決」されたときに呼び出す関数に追加する

    • deferred.fail()
      引数の関数を、Deferredオブジェクトが「拒否」されたときに呼び出す関数に追加する

    • deferred.notify()
      指定された引数を使用して、Deferredオブジェクトの progressCallbacks を呼び出す。

    • deferred.notifyWith()
      指定されたコンテキストと引数を使用して、Deferredオブジェクトの progressCallbacks を呼び出す。

    • deferred.progress()
      notify()やnotifyWith()で呼び出すprogressCallbacksを追加する

    • deferred.promise()
      Deferred の Promise オブジェクトを返す

    • deferred.reject()
      Deferredオブジェクトを「拒否」し、指定された引数を使用して failCallbacks を呼び出す

    • deferred.rejectWith()
      Deferredオブジェクトを「拒否」し、指定されたコンテキストと引数を使用して failCallbacks を呼び出す

    • deferred.resolve()
      Deferredオブジェクトを「解決」し、指定されたコンテキストと引数を使用して doneCallbacks を呼び出す

    • deferred.resolveWith()
      Deferredオブジェクトを「解決」し、指定されたコンテキストと引数を使用して doneCallbacks を呼び出す

    • deferred.state()
      Deferredオブジェクトの現在の状態("pending"か"resolved"か"rejected")を返す

    • deferred.then(doneFilter, [failFilter, progressFilter])
      Deferredオブジェクトのステータスごとに呼び出す関数を追加する

      • Deferredオブジェクトが「解決」の時は doneFilter
      • Deferredオブジェクトが「拒否」の時は failFilter
      • Deferredオブジェクトが「進行中」の時は progressFilter
    • .promise()
      キューに登録されているかどうかに関係なく、コレクションにバインドされている特定のタイプのすべてのアクションが完了したかどうかを確認するための Promise オブジェクトを返す

〇実際実装して確かめた

★resolveとthen

  1. Deferredオブジェクトを作ってresolveすることで、直後のthen()に進む
  2. resolve()の引数「5」は、直後のthen()の、1つ目の引数の関数(=doneFilter)に渡している
  3. 1つめのthen()の処理が終わったら次のthen()に進む
  4. then()の戻り値value * 2が次のthen()の引数として渡る
javascript
$.Deferred().resolve(5) // 1. 2.
  .then(function (value) { 
    return value * 2; // 4.
  })
  .then(function (value) { // 3.
    console.log(value);
  });
  // ⇒ コンソールに「10」が出力される

★promise, resolve, reject, notify

  1. Deferredオブジェクトを作り
  2. ステータスを設定し
  3. promiseオブジェクトを返している
  • この関数の呼び出しにthen()をつなげることで、ステータスごとの処理をこの処理の後に実行させることができる
javascript
  function asynchronousMethod() {
    // 1.
    var deferred = $.Deferred();
    var random = Math.floor(Math.random() * 10); // 0~9のランダムな数値
    // 2.
    if (random < 3) {
      deferred.resolve('Success'); // 偶数の場合は成功にする
    } else if (random < 6) {
      deferred.reject('Failure'); // 奇数の場合は失敗にする
    } else {
      deferred.notify('Notify'); // それ以外の場合は通知する
    }
    // 3.
    return deferred.promise(); // Promiseオブジェクトを返す
  }

★上記非同期関数(asynchronousMethod)の利用、done, fail, progress, always

  1. asynchronousMethodで返ってきたステータスによって実行される関数が決まる
  2. 成功(resolve)の場合は1番目の引数関数
  3. 失敗(reject)の場合は2番目の引数関数
  4. 通知(notify)の場合は3番目の引数関数
  5. 上記非同期関数のステータス設定時に引数に設定された値は、それぞれの関数の引数(value)で受け取る
  6. 1つめのthen()の結果で、成功であればdone、失敗であればfail、通知であればprogressが実行される
  7. alwaysは「解決」か「拒否」の時に実行されるので、「通知」の場合は実行されない
  • 1つめのthen()の失敗時の関数(failCallbacks)で、return $.Deferred().reject();がなければ、その後はdone()の関数が実行される
javascript
asynchronousMethod()
  .then( 
    function (value) {console.log('成功1:' + value)}  // 2.
    , function (value) {  // 3.
        console.log('失敗1:' + value);
        return $.Deferred().reject(); // 失敗の時に失敗を返すようにしている
    } 
    , function (value) {console.log('通知1:' + value)} // 4.
  ).done(                                 // 6.
    function () {console.log('成功3')}
  ).fail(
    function () {console.log('失敗3')} 
  ).progress(
    function () {console.log('通知3')}
  )
  .always(function () { // 7.
    console.log('完了');
  });

★when

  • when()は、deferred1deferred2両方でステータス設定されたら後続が実行される
  • 「5秒かかる処理」と「7秒かかる処理」は平行で実行されるので、最後の「全ての処理が完了しました」と出るのはより時間のかかる方の処理とほぼ同じ時間(約7秒)になる。5秒+7秒=12秒ではない。
javascript
let starttime = new Date().getTime();
var deferred1 = $.Deferred();
var deferred2 = $.Deferred();

$.Deferred().resolve()
.then(function () {
  // 5秒かかる処理
  setTimeout(function () {
    let countdiff1 = new Date().getTime() - starttime; // 約5秒
    console.log('deferred1:', countdiff1);
    deferred1.resolve();
    
  }, 5000);
});
$.Deferred().resolve()
.then(function () {
  // 7秒かかる処理
  setTimeout(function () {
    let countdiff2 = new Date().getTime() - starttime; // 約7秒
    console.log('deferred2:', countdiff2);
    deferred2.resolve();
  }, 7000);
});

$.when(deferred1, deferred2).done(function () {
  let countdiff3 = new Date().getTime() - starttime;  // 約7秒
  console.log('全ての処理が完了しました', countdiff3);
});

★whenその2

  • whenは、引数のdeferredのいずれかが失敗であれば、後続は失敗時の処理が実行される
javascript
let nowtimestamp = new Date().getTime();
var deferred1 = $.Deferred();
var deferred2 = $.Deferred();
var random = Math.floor(Math.random() * 10);

$.Deferred().resolve()
.then(function () {
  setTimeout(function () {
    deferred1.reject();
  }, 5000);
});
$.Deferred().resolve()
.then(function () {
  setTimeout(function () {
    deferred2.resolve();
  }, 7000);
});

$.when(deferred1, deferred2).then( 
  function () {console.log('成功:', new Date().getTime() - nowtimestamp)}
  , function () {console.log('失敗:', new Date().getTime() - nowtimestamp)} // こっち
);

■まとめ

  • $.Deferred()は、Deferredオブジェクト を用意する関数
  • Deferredオブジェクトは、登録した「コールバック関数」の実施タイミングや順番を操るメソッドをもつ
  • 非同期関数同士が複数あるときに、並列で実行させたり直列で実行させたり制御することができる

ステータス設定するメソッド

メソッド 引数 概要
resolve 型自由の値
(後続に値を渡す)
ステータスを成功にする
reject ステータスを失敗にする
notify ステータスを通知にする

コールバック関数用意するメソッド

メソッド 引数 概要
then 成功時実行関数
失敗時実行関数
通知時実行関数
つながってる直前の処理のステータス(成功/失敗/通知)ごとに呼び出すコールバック関数を用意
done 成功時実行関数 つながってる直前の処理のステータスが成功のときに呼び出すコールバック関数を用意
fail 失敗時実行関数 つながってる直前の処理のステータスが失敗のときに呼び出すコールバック関数を用意
progress 通知時実行関数 つながってる直前の処理のステータスが通知のときに呼び出すコールバック関数を用意
always 成功or失敗時実行関数 つながってる直前の処理のステータスが成功/失敗どちらかの時に共通して呼び出すコールバック関数を用意

Promiseオブジェクトを返すメソッド

メソッド 引数 概要
promise オブジェクト
(Promise にできる)
Promiseオブジェクトを返す

複数のDeferredオブジェクトを監視しているメソッド

メソッド 引数 概要
when Deferred
オブジェクト
引数のオブジェクト全てでステータス設定されたら後続実行
2
1
1

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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?