Promise và $q trong Angularjs
Mình tự hỏi q là gì trong Angularjs. Và mình bắt đầu đi tìm hiểu? q service tạo ra các promises. Vậy Promises là j? Promises là gì? Promise là 1 cơ chế cho phép bạn bạn trì hoãn 1 hành động hoặc 1 chuỗi hành động đã được nêu ra. Một promise đại diện cho kết quả sau cùng của một hành động. Ví Dụ ...
Mình tự hỏi q là gì trong Angularjs. Và mình bắt đầu đi tìm hiểu? q service tạo ra các promises. Vậy Promises là j? Promises là gì? Promise là 1 cơ chế cho phép bạn bạn trì hoãn 1 hành động hoặc 1 chuỗi hành động đã được nêu ra. Một promise đại diện cho kết quả sau cùng của một hành động. Ví Dụ như hành động B chỉ chạy khi hành động A làm xong công việc dù thanh công hay thất bại. Và chức năng của promise là sử lý các hành động không đồng bộ (Asynchronous). Vậy hành động không đồng bộ là gì? Asynchronous là xử lý không đồng bộ. Nghĩa là chương trình có thể bỏ qua 1 bước nào đó. VD khi tôi viết chương trình: "Tối nay tôi sẽ đi tán gái , trước khi đi tán gái tôi phải mua iphone 7 plus". Vậy Asynchronous là : Tối có thể đi tán gái luôn và không phải mua iphone 7 plus. Ex:
var app = angular.module('myApp', []); app.controller('myCtrl', function($scope, $http, $timeout) { $scope.message = "Tao đi tán gái <3" $http({ method : 'GET', url : '/byephone' }).then (function success(response){ $timeout(function(){ $scope.message = 'Tao đã mua 7 plus, Giờ tao đi tán gái'; }, 5000); )}, function error(response){ $scope.message = 'Tao không đủ tiền mua, Tao đi về'; }); alert(message); });
Lúc này đoạn alert(message) = "Tao đi tán gái " Theo quy trình xử lý thì chương trình sẽ biên dịch từ trên xuống dưới , từ trái sang phải . Nhưng do Ajax phải mất 1 khoảng thơi gian để request tới url và 5s timeout nữa. Nên dẫn đến việc $scope.message chưa thay đổi khi chương trình chạy tới alert(message);
Vì vậy làm thế nào để message nhận kết quả khi server trả về. c1: Ta có thể setTimeout Async cho alert(message) Vì bản chất setTimeout cũng là 1 Async. $timeout(message, 10000); (bạn có thể dùng setTimeout với angularjs cơ mà cần sử dụng thêm $scope.$apply();)
c2: chính là phần mình để cập tới đây khi dùng promise. Promise sẽ giúp đồng bộ hóa các tiến trình. Vậy đồng bộ hóa là gì? Synchronous có nghĩa là xử lý đồng bộ hóa. Túc là chương trình sẽ chạy theo từng bước. Và chỉ chạy sang bước 2 khi thực hiện xong bước 1. Nó sinh ra 1 trạng thái gọi là trạng thái chờ. Nó đúng với tên Promise (hẹn ước) 'Mày phải có iPhone 7 thì Tao mới yêu'.
Do synchronous và Asynchronous là 2 khái niệm đối nghịch nhau nên ưu điểm của các này là nhược điểm của cái khác ở synchronous chúng ta dễ nhận thấy : Chương trình chạy tuần tự và có nguyên tác sẽ không mắc lỗi về tiến trình. Khi chúng ta đăng ký tạo 1 form đăng ký và validate. Sẽ xảy ra lỗi khi form đc add mà validate chưa kiểm tra xong. tuy nhiên ở asynchronous dễ nhận thấy hệ thống có thể chạy nhiều tiến trình cùng 1 lúc sẽ không bị tràn bộ nhớ vì phải lưu những trạng thái chờ không cần thiết. Ở synchronous mình chưa đưa ví dụ vì mình sẽ đề cập ở phần sau. Giờ hiểu rõ bản chất rồi. Đi vào vấn đề chính thôi.
Promise là cho phép trì hoãn 1 hành động đang được thực thi. Cách làm việc của Promise sẽ gồm
Ta thế Deferred sẽ được hiểu là 1 công việc chưa được thực hiện. Promise là kết quả của công việc đó. Khi có kết quả trả về. Nó sẽ có 2 trạng thái là Handlers và State. Handlers sẽ thực hiện gọi các hàm callback để tiếp tục thực hiện. State sẽ có 3 trạng thái nhất định : waiting, success, error.
Ở trên là các thức hoạt động của promise. về riêng Angular thì promise được tạo bởi $q service. $q noó cũng tạo bởi các service khác như : $http, $timeout, $route, $resource. Thực chất ra sơ đồ trên là miêu tả thực thi của $$.
**q và 1 số phương thức riêng**: `q.defer()- tạo mới 1 đối tượng deferred,q.all()` - cho phép bạn chờ nhiều promises để giải quyết, `q.when(), q.resolve` khi chúng ta muốn resole 1 promise từ object không phải promise. `q.reject()` dùng khi bạn muốn reject 1 promise....
- $q.defer : tạo mới 1 đối tượng deferred bao gồm các phương thức :
-
$resolve() : khi muốn 1 object không phải promise thành promise
-
$reject() : khi muốn reject 1 promise
-
$notity() : gọi method callback trước khi promise được resolved or reject
.factory('example', ['$http', '$q', function($http, $q){ return { function(method, url, params) { var def = $q.defer(); //khởi tạo deferrend def.notify('I love U <3'); $http({method: method, url: url, params: params}) .success(function(res){ def.resolve('You too <3'); }) .error(function(err){ def.reject('FA'); }) return def.promise; } }}]); var promise = example(); promise.then(function(response){ alert(response); })
-
2.$q.all(): tập hợp các promise. và chỉ trả về giá trị khi các promise bên trong đã được giải quyết. Có thể gọi với 1 array or 1 object VD: Tôi tuyển người yêu. Và tôi chỉ quyết định khi cô A và cô B đều đứng trước mặt tôi để tôi lựa chọn ex:
.facroty('example', ['$http', '$q', function($http, $q){ var girlOne = $q.defer(); var girlTwo = $q.defer(); $q.all([girlOne.promise, girlTwo.promise]).then(funtion(response){ console.log(response); }); $timeout(function(success){ girlOne.resolve('xấu, nhà giầu'); }, 1000); $timeout(function(success){ girlTwo.resolve('xinh, nhà nghèo'); }, 2000); }]); // ['xấu, nhà giầu','xinh, nhà nghèo']'
Như mọi người thấy mình set timeout cho 2 cô gái A và B. nếu ta dùng $q.all thì kết quả sẽ trả về khi girlOne và girlTwo hoàn thành xong 3.$q.race() : trả về 1 promise đc reslove đầu tiên. Như VD trên khi thay q.all()=q.all() = q.all()=q.race() thì kết quả sẽ trả về xấu, nhà giầu 4.$q.when(): sẽ trả về khi GirlOne xong, sau đó girlTwo xong. ex:
$q.when(girlOne).then(function(response){ $scope.girl = response; }); $q.when(girlTwo).then(function(response){ $scope.girl = response; });
Thì ở dây scope.girl = "xấu, nhà giầu" và sau khi girlTwo chạy xong thì scope.girl = "xinh, nhà nghèo"... Kết: Bằng việc sử dụng Promise và $$ chúng ta có thể sử dụng nó để xử lý việc bất đồng bộ trong AngularJS. Tuy nhiên Synchronous và Asynchronous đều có mặt ưu và nhược. Nên mọi người cố gắng xử lý theo từng tình hướng và trường hợ cụ thể nhé.