11/08/2018, 20:16

Tìm hiểu về Javascript Promise

Trong bài AngularJS cho người mới: Dependencies và Services cũng như một số bài viết khác tôi đã có đề cập đến khái niệm promise trong Javascript, hôm nay tôi sẽ giới thiệu rõ hơn về promise cũng như ý nghĩa là tác dụng của nó. Nào cùng bắt đầu nhé. Promise là gì? Promise được sinh ra để ...

Trong bài AngularJS cho người mới: Dependencies và Services cũng như một số bài viết khác tôi đã có đề cập đến khái niệm promise trong Javascript, hôm nay tôi sẽ giới thiệu rõ hơn về promise cũng như ý nghĩa là tác dụng của nó. Nào cùng bắt đầu nhé.

Promise là gì?

Promise được sinh ra để thể hiện cho kết quả sau cùng của một tác vụ bất đồng bộ (asynchronous operation). Nó là một placeholder mà trong nó kết quả của việc thực thi tác vụ bất đồng bộ đó dù thành công hay thất bại sẽ được hiện thực.

Tại sao lại sử dụng Promise?

Nếu so sánh với các phướng thức callback-based truyền thống thì promise cung cấp một biện pháp thay thế đơn giản hơn trong việc thực thi, biên soạn và quản lý các tác vụ bất đồng bộ. Hơn cả, promise cho phép chúng ta handle các lỗi xảy ra khi thực thi tác vụ bất đồng bằng các sử dụng các phương thức tiếp cận tương tự với sử dụng try/catch trong các tác vụ đồng bộ (synchronous) thông thường.

Promise States

Promise có thể ở một trong ba trạng thái.

  • Pending – trang thái khởi tạo, lúc này kết quả của promise vẫn chưa được xác định, bởi vì tác vụ bất đồng bộ vẫn chưa hoàn thành.
  • Fullfilled – trạng thái hoàn thành, tác vụ bất đồng bộ đã hoàn thành, và promise đã có giá trị.
  • Rejected – trạng thái bị từ chối, tác vụ bất đồng bộ thực thi thất bại, và promise sẽ không bao giờ được hoàn thành (fullfilled). Trong trạng thái bị từ chối (rejected) một promise sẽ chứa một lý do (reason) để chỉ ra tại sao việc thực thi thất bại.

Khi một promise đang ở trạng thái khởi tạo (pending), nó có thể chuyển sang trạng thái hoàn thành (fullfilled) hoặc bị từ chối (rejected). Một khi promise được hoàn thành hoặc bị từ chối, thì đó sẽ là giá trị cuối cùng, promise đó sẽ không thể chuyển thành trạng thái khác được nữa, và vì thế giá trị của nó hoặc lý do thực hiện thất bại sẽ không thay đổi.

Sử dụng Promise

Điểm quan trọng nhất của một API cho promise chính là phương thức then(), đây chính là cái mà các callback đăng kí vào để nhận giá trị trả về hay lý do promise không thể hoàn thành. Dưới đây là một đoạn code “hello world” được viết dưới dạng thông thường (synchronous).

var greeting = sayHello();
console.log(greeting); // 'hello world’

Tuy nhiên, nếu phương thức sayHello là một phương thức bất đồng bộ, và cần lấy dữ liệu từ một web service nào đó trả về, chúng ta có thể chuyển nó thành promise như sau.

var greetingPromise = sayHello();
greetingPromise.then(function (greeting) {
    console.log(greeting); // 'hello world’
});

Message vẫn được in ra console, nhưng giờ đây, những block code khác có thể tiếp tục chạy khi lời chào đang được fetch.

Như tôi đã nói ở trên, một promise có thể đại diện cho một thất bại. Nếu như network có vấn đề và lời chào không thể được fetch từ web service, chúng ta có thể đăng kí một callback để giải quyết các lỗi bằng cách sử dụng tham số thứ hai của phương thức then như sau.

var greetingPromise = sayHello();
greetingPromise.then(function (greeting) {
    console.log(greeting); // 'hello world’
}, function (error) {
    console.error('something went wrong: ', error);   // 'something went wrong: blabla’
});

Nếu sayHello thành công, lời chào sẽ được in ra console, nhưng nếu nó thất bại, thì lý do thất bại sẽ được in ra console bằng console.error.

Chuyển đổi giá trị trong tương lai

Một khía cạnh mạnh mẽ của promise là cho phép chúng ta có thể chuyển đổi giá trị trả về trong tương lai bằng việc trả về một giá trị mới trong callback và truyền nó vào trong phương thức then. Ví dụ.

var greetingPromise = sayHello();
greetingPromise.then(function (greeting) {
    return greeting + '!';
}).then(function (greeting) {
    console.log(greeting); // 'hello world!’
});

Chuỗi các tác vụ bất đồng bộ

Một function được truyền vào then có thể trả về giá trị là một promise khác. Điều này cho phép các tác vụ bất động bộ tạo thành một chuối mắt xích với nhau, cũng vì thế mà có thể dảm bảo rằng chúng xảy ra theo thứ tự đúng đắn. Lấy ví dụ, nếu hàm thêm dấu “!” (addExclamation) là một tác vụ bất đồng bộ và trả về một promise để các hàm gọi lời chào tiếp theo được thực hiện như sau.

var greetingPromise = sayHello();
greetingPromise.then(function (greeting) {
    return addExclamation(greeting); // addExclamation returns a promise
}).then(function (greeting) {
    console.log(greeting); // 'hello world!’
});

Thì chúng ta có thể viết một cách đơn giản hơn như sau.

var greetingPromise = sayHello();
greetingPromise
    .then(addExclamation)
    .then(function (greeting) {
        console.log(greeting); // 'hello world!’
    });

Xử lý lỗi

Điều gì xảy ra nếu có lỗi trong khi thực hiện tác vụ bất đồng bộ? ví dụ như hàm sayHello, hoặc addExclamation bị fail?

Trong code synchronous, chúng ta sử dụng try/catch and dựa vào exception để handle lỗi. Dưới đây sẽ là các code synchronous thông thường, dùng try/catch để xử lý lỗi. Nếu có lỗi xảy ra, thì catch block sẽ được thực thi, in lỗi ra console.

var greeting;
try {
    greeting = sayHello();
    greeting = addExclamation(greeting);
    console.log(greeting); // 'hello world!’
} catch(error) {
    console.error('something went wrong: ', error);   // 'something went wrong: blabla’
}

Khi thực hiện với các tác vụ bất đồng bộ, try/catch block ko thể sử dụng được nữa. Tuy nhiên, promise cho phép chúng ta handle lỗi của các tác vụ bất đồng bộ bằng cách đơn giản hơn, không chỉ cho phép chúng ta viết code asynchronous tương tự với style code synchronous, mà còn kiểm soát được flow và handle lỗi tương tự như synchronous code.

Dưới đây và phiên bản asynchronous dùng để handle lỗi.

var greetingPromise = sayHello();
greetingPromise
    .then(addExclamation)
    .then(function (greeting) {
        console.log(greeting); // 'hello world!’
    }, function(error) {
        console.error('something went wrong: ', error); // 'something went wrong: blabla’
    });

Hy vọng qua những điều hướng dẫn cơ bản đã nêu ra, các bạn đã có thể hiểu được promise trong javascipt là gì, làm thế nào để sử dụng cũng như áp dụng promise vào các trường hợp thực tế.

Chào tạm biệt và hẹn gặp lại.

Bài gốc: https://codeaholicguy.wordpress.com/2016/01/26/tim-hieu-ve-javascript-promise/

0