Promises trong AngularJS

Giới thiệu
Promises trong Angular JS được cung cấp thông qua đối tượng $q ,mục đích là để thực hiện chức năng động bộ 1 chuỗi các chức năng bằng cách đăng kí vào các promises.

Đăng ký promises

<html>
    <head>
        <title>Promise fun</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0-beta.5/angular.min.js"></script>
        <script src="app.js"></script>
    </head>
    <body ng-app="app">
    </body>
</html>
function getData($timeout, $q) {
  return function() {
    var defer = $q.defer()

    // simulated async function
    $timeout(function() {
    }, 2000)

    return defer.promise
  }
}

angular.module('app', [])
.factory('getData', getData)
.run(function(getData) {
  var promise = getData()
})

Để đơn giản, chúng ta sẽ sử dụng các dịch vụ $ timeout () để mô phỏng một chức năng không đồng bộ.Trong đoạn javascript trên,tôi đã thực hiện việc đăng kí 1 promise là function getData.

Deferred Object
Deferred Objec là đối tượng thực hiện các promise trong angular js,được xây dựng bằng cách khai báo phương thức : $q.defer(),đồng thời đưa thêm 3 action chính :resolve(), reject(), and notify().

function getData($timeout, $q) {
  return function() {
    var defer = $q.defer()

    // simulated async function
    $timeout(function() {
      defer.resolve('data received!')
    }, 2000)

    return defer.promise
  }
}

Trong đoạn code trên,toi đã tạo 1 deffered object và trả lại với object của promise.Các parameter của function resolve sẽ được gửi thông qua các function call back.
Promise Object
Giờ tôi sẽ khởi tạo 1 Promise object (defer.promise) và khi refresh the page, dòng chữ "data received!" sẽ được hiện ra ở màn hình console sau 2 giây:

.run(function(getData) {
  var promise = getData()
    .then(function(string) {
      console.log(string)
    })
})

trong quá trình sử lý các promises nếu có xảy ra lỗi ,ta có thể sử dụng function reject() để xử lí các lỗi phát sinh như :

function getData($timeout, $q) {
  return function() {
    var defer = $q.defer()

    // simulated async function
    $timeout(function() {
      if(Math.round(Math.random())) {
        defer.resolve('data received!')
      } else {
        defer.reject('oh no an error! try again')
      }
    }, 2000)
    return defer.promise
  }
}

Promise Chaining
Một trong những tính năng nổi bật nhất của Promises là khả năng kết nối các function,cho phép xâu chuỗi lại data,quản lý data theo từng bước.Sau đây là ví dụ sử dụng Chaining trong Promises:

function getData($timeout, $q) {
  return function() {
    // simulated async function
    return $q(function(resolve, reject) {
      $timeout(function() {
        resolve(Math.floor(Math.random() * 10))
      }, 2000)
    })
  }
}

sau khi người dùng refresh page sẽ hiện thị ngẫu nhiên 1 số từ 0 đến 9.Để bắt đầu thực hiện việc chaining,t sẽ refactor lại hàm callback

.run(function(getData) {
  var promise = getData()
    .then(function(num) {
      console.log(num)
      return num * 2
    })
})

Giờ ta có thể gọi 1 function callback khác trong object promises bằng cách sử dùng function then() .Function này sẽ được thực thi ngay sau khi function đầu tiên thực thi xong và giá trị number được trả ra trong function callback sẽ đc gán tiếp vào function tiếp theo :

.run(function(getData) {
  var promise = getData()
    .then(function(num) {
      console.log(num)
      return num * 2
    })
    .then(function(num) {
      console.log(num) // = random number * 2
    })
})

Bên cạnh việc trả về kết quả của 1 function,bạn có thể trả về 1 object Promises mới.và chuỗi chaining của promise sẽ tạm dừng cho đến khi promise trả về thực thi xong,đảm bảo thực hiện đồng bộ dữ liệu khi bạn có nhiều request tới server.