3分でわかるAngularJSの$qサービスのPromise Deferred then all finally

3分でわかるAngularJSの$qサービスのPromise Deferred then all finally

Promiseとは

非同期処理に使用するオブジェクト

使い方

まず$qサービスを使用するため以下の形を作る

var app = angular.module('app', []);
app.controller('Ctrl', function($q) {

});

そして非同期処理用の関数を作成。var deferred = $q.defer();で非同期処理に必要なDeferredオブジェクトを作成して処理の最後にreturn deferred.promiseで返す

function async() {
  var deferred = $q.defer();
  // この中に処理を記述
  return deferred.promise;
}

名前を受け取ってHello付けて返す処理の場合はこのようになる

function asyncHello(name) {
  var deferred = $q.defer();
  deferred.resolve('Hello, ' + name);
  return deferred.promise;
}

deferred.resolve()は成功時のpromise処理

promise.then(function(){})を追加

引数部分はこの場合deferred.resolve('Hello, ' + name)の内容になる

var promise = asyncHello('sato');
promise.then(
  function(msg) {
    r.innerHTML = msg;
  }
);

AngularJS $q Promise サンプル01

1秒遅らせて処理したい場合

$timeoutサービスを追加してvar deferred = $q.defer();とreturn deferred.promise;の間を$timeoutで囲む

function asyncHello(name) {
  var deferred = $q.defer();
  $timeout(function() {
    deferred.resolve('Hello, ' + name);
  }, 1000);
  return deferred.promise;
}

AngularJS $q Promise サンプル02

失敗時のpromise処理 reject()

成功時のpromise処理はresolve()なのに対し、失敗時の処理にはreject()を使用する。例えばnameが文字列の時は成功、文字列以外の時は失敗の処理をしたい場合は下記のようになる。

then()内の第1引数にresolve、第2引数にrejectのコールバック関数を記述する

var app = angular.module('app', []);
app.controller('Ctrl', function($q, $timeout) {
  function asyncHello(name) {
    var deferred = $q.defer();
    $timeout(function() {
      if(typeof(name) === 'string') {
        deferred.resolve('Hello, ' + name);
      }
      else {
        deferred.reject(name + 'は文字列ではありません。');
      }
    }, 1000);
    return deferred.promise;
  }
  var r = document.getElementById('result');
  var promise = asyncHello(326);
  promise.then(
    function(msg) {
      r.innerHTML = msg;
    },
    function(msg) {
      r.innerHTML = msg;
    }
  );
});

AngularJS $q Promise サンプル03

通知のpromise処理 notify()

通知の処理にはnotifyを使用する。成功、失敗に関わらない処理に使用。

then()内の第3引数にnotifyのコールバック関数を記述する

var app = angular.module('app', []);
app.controller('Ctrl', function($q, $timeout) {
  function asyncHello(name) {
    var deferred = $q.defer();
    $timeout(function() {
      deferred.notify(name + 'を受け取りました。');
      if(typeof(name) === 'string') {
        deferred.resolve('Hello, ' + name);
      }
      else {
        deferred.reject(name + 'は文字列ではありません。');
      }
    }, 1000);
    return deferred.promise;
  }
  var r = document.getElementById('result');
  var promise = asyncHello('sato');
  promise.then(
    function(msg) {
      r.innerHTML += msg;
    },
    function(msg) {
      r.innerHTML += msg;
    },
    function(msg) {
      r.innerHTML += msg + '<br>';
    }
  );
});

AngularJS $q Promise サンプル04

asyncHelloを2回使用する場合

var app = angular.module('app', []);
app.controller('Ctrl', function($q, $timeout) {
  function asyncHello(name) {
    var deferred = $q.defer();
    $timeout(function() {
      deferred.notify(name + 'を受け取りました。');
      if(typeof(name) === 'string') {
        deferred.resolve('Hello, ' + name);
      }
      else {
        deferred.reject(name + 'は文字列ではありません。');
      }
    }, 1000);
    return deferred.promise;
  }
  var r = document.getElementById('result');
  var p1 = asyncHello('sato');
  var p2 = asyncHello(326);

  var successCallback = function(msg) {
    r.innerHTML += msg + '<br>';
  };
  var errorCallback = function(msg) {
    r.innerHTML += msg + '<br>';
  };
  var notifyCallback = function(msg) {
    r.innerHTML += msg + '<br>';
  };

  p1.then(successCallback, errorCallback, notifyCallback);
  p2.then(successCallback, errorCallback, notifyCallback);
});

AngularJS $q Promise サンプル05

promise.catch(errorCallback)

promise.then(null, errorCallback)と同じ。

$q.all()ですべての処理を監視

$q.all()を使用すればすべての処理が完了した後の処理を実行できる。

var app = angular.module('app', []);
app.controller('Ctrl', function($q, $timeout) {
  function asyncHello(name) {
    var deferred = $q.defer();
    $timeout(function() {
      deferred.notify(name + 'を受け取りました。');
      if(typeof(name) === 'string') {
        deferred.resolve('Hello, ' + name);
      }
      else {
        deferred.reject(name + 'は文字列ではありません。');
      }
    }, 1000);
    return deferred.promise;
  }
  var r = document.getElementById('result');
  var p1 = asyncHello('sato');
  var p2 = asyncHello(326);

  var successCallback = function(msg) {
    r.innerHTML += msg + '<br>';
  };
  var errorCallback = function(msg) {
    r.innerHTML += msg + '<br>';
  };
  var notifyCallback = function(msg) {
    r.innerHTML += msg + '<br>';
  };

  var p1End = p1.then(successCallback, errorCallback, notifyCallback);
  var p2End = p2.then(successCallback, errorCallback, notifyCallback);

  $q.all([p1End, p2End]).then(
    function() {
      r.innerHTML += 'すべての処理が完了しました。';
    }
  );
});

AngularJS $q Promise サンプル06

thenのあとに実行するfinally

then().finally(finallyCallback())でthen実行後の処理を追加できる

var finallyCallback = function(msg) {
  r.innerHTML += 'thenの処理が完了しました。<br>';
};

var p1End =
  p1
  .then(successCallback, errorCallback, notifyCallback)
  .finally(finallyCallback);

AngularJS $q Promise サンプル07