Monday, April 9, 2018

Tìm hiểu về $q và Promise trong Angular

 
$q và Promise trong Angular

Chắc hẳn mọi người đều đã từng nhìn thấy hoặc đã từng làm việc với $q khi sử dụng angular, chăng bạn có chắc đã nắm được hết những tính năng tuyệt với của nó mang lại như là $q.all() , $q.race(). Bài viết này mình sẽ nói về một vài điều hay ho về nó.

Promise là cái quái gì ?

Promise là một type đặc biệt của 1 Object có thể sử dụng hay để cấu trúc việc xử lý bất đồng bộ. Tại sao lại gọi nó là “Promise” có lẽ cũng giống như nghĩa của nó “hẹn ước” :)) nếu A hoàn thành thì B thực hiện, nó sẽ trả về 1 kết quả ở 1 thời điểm nào đó trong tương lai.

Một Promise có 3 trạng thái pending resolved và rejected . Xử dụng $q trong Angular chúng ta có thể xấy dựng và xử lý được các promises của nó. (có lẽ nói đến đấy thấy hơi khó hiểu vì mình cũng ko hiểu mình đang nói cái … gì :)))

Để làm rõ cái “hồ mơ” trên thì chúng ta sẽ bắt đầu với 1 ví dụ làm quen với Promise trong ES2015.

ES5 Promises

Những cái chính đề cập tới ở đây sẽ là Promise, resolve, và reject

123 new Promise ( /* executor*/ function ( resolve , reject )  . . .  ) ;  
chúng ta chỉ cần khai báo new Promise() vào xử lý các tác vụ bất đồng bộ bên trong. Ví dụ
123456789101112131415161718192021222324252627282930313233 /* ES5 */var isHaveMoney = false ; // Promisevar willDrinkBeer = new Promise (     function ( resolve , reject )          if ( isHaveMoney )              var happy =    "Happy"             resolve ( happy ) ;          else              var reason = new Error ( 'So bad' ) ;             reject ( reason ) ;               ) ; // call our promisevar checkMoney = function ( )      willDrinkBeer         . then ( function ( fulfilled )              // yeah chúng ta có tiền và có bia             console . log ( fulfilled ) ;          )         . catch ( function ( error )              // ví hết tiền, chịu thôi !             console . log ( error . message ) ;          ) ; checkMoney ( ) ; // kết quả chắc chắn là không có tiền rồi vì ông trời set default ở trên là isHaveMoney = false; rồi :(((  

Giới thiệu $q

$q là một thành phần của AngularJS nó giống như Promise trong ES5. vì thế chúng ta có thể thực hiện như sau:

12345678910111213 let promise = $ q ( ( resolve , reject ) = >    if ( /* some async task is all good */ )      resolve ( 'Success!' ) ;    else      reject ( 'Oops... something went wrong' ) ;     ) ; promise . then ( data = >    console . log ( data ) ; ) ; 

Khác thay vì new Promise() chúng ta chỉ cần $q() và cách thực hiện của nó trong 1 service ở angular như sau :
12345678910111213141516171819 function MyService ( $ q )    return      getSomething ( )        return $ q ( ( resolve , reject ) = >          if ( /* some async task is all good */ )            resolve ( 'Success!' ) ;          else            reject ( 'Oops... something went wrong' ) ;                  ) ;         ; angular   . module ( 'app' )   . service ( 'MyService' , MyService ) ; 
Chúng ta có thể tạo ra 1 đối tượng Promise như thế này :
12345678910111213 function getStuff ( )    return $ http     . get ( '/api/stuff' ) ;     . then ( data = >        console . log ( 'Boom!' , data ) ;       ) ; getStuff ( ) . then ( data = >    console . log ( 'Boom!' , data ) ; ) ; 
chúng ta không nên tạo ra 1 đối tượng Promise như thế này vì nó sẽ tạo ra một đối tương Promise mới từ Promise đã tồn tại :

1234567891011121314151617181920 function getStuff ( )    // don't do this!   let defer = $ q . defer ( ) ;   $ http     . get ( '/api/stuff' ) ;     . then ( response = >        // don't do this!       $ q . resolve ( response ) ;      , reason = >        // don't do this!       $ q . reject ( reason ) ;      ) ;   return defer . promise ; getStuff ( ) . then ( data = >    console . log ( 'Boom!' , data ) ;  ) ; 

$q.defer()

Sử dụng $q.defer() như một thành phần nguyên thủy của $q, giống như cấu trúc của một Promise

123456789101112131415 function MyService ( $ q )    return      getSomething ( )        let defer = $ q . defer ( ) ;       if ( /* some async task is all good */ )          defer . resolve ( 'Success!' ) ;        else          defer . reject ( 'Oops... something went wrong' ) ;               return defer . promise ;         ;


$q.when() / $q.resolve()

Sử dụng $q.when() hoặc $q.resolve() ($q.resolve() là một alias của $q.when()) khi chúng ta muốn resolve một Promise từ Object không phải Promise.

1234567891011 $ q . when ( 123 ) . then ( res = >    // 123   console . log ( res ) ; ) ; $ q . resolve ( 123 ) . then ( res = >     // 123   console . log ( res ) ; ) ; 
$q.reject()

Sử dụng $q.reject() khi bạn muốn reject một Promise
123456789101112 $ httpProvider . interceptors . push ( $ q = > (     request ( config )  . . .  ,   requestError ( config )      return $ q . reject ( config ) ;    ,   response ( response )  . . .  ,   responseError ( response )      return $ q . reject ( response ) ;    ) ) ; 
$q.all()

Khi bạn cần resolve nhiều promise một lần bằng cách truyền vào 1 array các promise, cái này sẽ thực hiện .when() sau khi resolved

123456789101112131415161718 let promiseOne = $ http . get ( '/api/todos' ) ;let promiseTwo = $ http . get ( '/api/comments' ) ; // Array of Promises$ q . all ( [ promiseOne , promiseTwo ] ) . then ( data = >    console . log ( 'Both promises have resolved' , data ) ; ) ; // Object hash of Promises// this is ES2015 shorthand for promiseOne: promiseOne, promiseTwo: promiseTwo  $ q . all (      promiseOne ,     promiseTwo    ) . then ( data = >    console . log ( 'Both promises have resolved' , data ) ; ) ;


$q.race()

Tương tự như $q.all() phương thức $q.race() chỉ trả về 1 promise được resolve đầu tiên, ví dụ API 1 và API 2 cùng thực hiện, API 2 được resolve trước thì nó chỉ lấy Object được trả về từ API 2.
 


123456789101112131415161718 let promiseOne = $ http . get ( '/api/todos' ) ;let promiseTwo = $ http . get ( '/api/comments' ) ; // Array of Promises$ q . race ( [ promiseOne , promiseTwo ] ) . then ( data = >    console . log ( 'Fastest wins, who will it be?...' , data ) ; ) ; // Object hash of Promises// this is ES2015 shorthand for promiseOne: promiseOne, promiseTwo: promiseTwo  $ q . race (      promiseOne ,     promiseTwo    ) . then ( data = >    console . log ( 'Fastest wins, who will it be?...' , data ) ; ) ; 

Kết luận

Bằng việc sử Promise và $q chúng ta có thể xử lý đựọc bất đồng bộ trong AngularJS, và sử dụng $q.all() hoặc $q.race() để xử lý các promise đã có.

Đây là những tìm hiểu của mình về Promise trong ES5 cũng như $q trong AngularJS nhằm giải quyết các vấn đề bất đồng bộ. hy vọng sẽ có ích cho mọi người.
 

No comments:

Post a Comment