ASYNC LÀ GÌ

Chời, thời này ai xài Promise nữa. Chuẩn hiện nay là async/await.-- Ai đó trên mạng

Hãy khoan các bạn ơi, chớ vội vàng nhảy lên chuyến tàu tốc hành async/await trong lúc không rành Promise, kẻo lại xẩy ra "va đụng lúc dồn dịch", gây nên hậu quả khó lường, vị căn uống bạn dạng async/await vẫn dùng Promise nghỉ ngơi bên dưới nhưng thôi.

Bạn đang xem: Async là gì

millionarthur.mobi vẫn điểm hồ hết khái niệm căn uống phiên bản về Promise, bên cạnh đó so sánh cùng với async/await giúp thấy bao giờ thì nên cần xài sản phẩm làm sao nhé.

Nhắc lại, Promise là gì?

Promise là một cơ chế vào JavaScript giúp cho bạn thực hiện các tác vụ bất đồng hóa mà không rơi vào tình thế callback hell giỏi pyramid of doom, là tình trạng các hàm callback lồng vào nhau sống không ít tầng. Các tác vụ bất nhất quán có thể là gửi AJAX request, Hotline hàm bên trong setTimeout, setInterval hoặc requestAnimationFrame, tuyệt thao tác với WebSocket hoặc Worker... Dưới đây là một callbaông xã hell nổi bật.

api.getUser('pikalong', function(err, user) if (err) throw err api.getPostsOfUser(user, function(err, posts) if (err) throw err api.getCommentsOfPosts(posts, function(err, comments) // vân vân cùng mây mây... ) ) )lấy ví dụ trên Lúc được viết lại bởi Promise vẫn là:

api .getUser('pikalong') .then(user => api.getPostsOfUser(user)) .then(posts => api.getCommentsOfPosts(posts)) .catch(err => throw err )Để tạo thành một promise object thì các bạn sử dụng class Promise có sẵn trong trình coi xét nhỏng sau:

const p = new Promise( /* executor */ function(resolve sầu, reject) // Thực thi những tác vụ bất đồng bộ ở đây, với gọi `resolve(result)` Khi tác // vụ hoàn thành. Nếu xảy ra lỗi, gọi đến `reject(error)`. , )Trong đó, executor là 1 trong hàm gồm hai tđắm đuối số:

resolve là hàm sẽ tiến hành gọi Khi promise hoàn thànhreject là hàm sẽ được Hotline Khi có lỗi xảy ra

Ví dụ:

api.getUser = function(username) // Hàm api.getUser() trả về một promise object return new Promise((resolve, reject) => // Gửi AJAX request http.get(`/users/$username`, (err, result) => // Nếu gồm lỗi bên phía trong callbachồng, bọn họ gọi đến hàm `reject()` if (err) return reject(err) // Ngược lại, cần sử dụng `resolve()` để trả dữ liệu về mang lại `.then()` resolve(result) ) ) Bởi vậy api.getUser() đã trả về một promise object. Chúng ta rất có thể truy nã xuất đến kết quả trả về bởi cách thức .then() như sau:

function onSuccess(user) console.log(user) function onError(err) console.error(error) api.getUser('pikalong').then(onSuccess, onError)Phương thức .then(onSuccess, onError) nhận vào nhị hàm: onSuccess được Gọi Lúc promise dứt với onError được điện thoại tư vấn Khi có lỗi xẩy ra. Bên vào tmê mẩn số onSuccess bạn cũng có thể trả về một quý hiếm nhất quán, ví dụ như cực hiếm số, chuỗi, null, undefined, array xuất xắc object; hoặc một promise object khác. Các giá trị bất đồng bộ sẽ được bọc phía bên trong một Promise, được cho phép các bạn liên kết (chaining) nhiều promises lại với nhau.

promise() .then(() => return 'foo' ) .then(result1 => console.log(result1) // 'foo' return anotherPromise() ) .then(result2 => console.log(result2)) // `result2` sẽ là kết quả của anotherPromise() .catch(err => )Trong ví dụ trên, bạn thấy đến cách làm .catch(). Pmùi hương thức này chỉ với cú pháp bọc đường (syntactic sugar) của .then(null, onError) mà thôi. Chúng ta đang nói thêm về .catch() làm việc bên dưới.

Tạo nkhô hanh Promise cùng với Promise.resolve() với Promise.reject()

Có hầu như ngôi trường đúng theo chúng ta chỉ cần bọc một cực hiếm vào promise tuyệt auto reject. Thay vị dùng cú pháp new Promise() lâu năm mẫu, bạn cũng có thể sử dụng nhị cách làm tĩnh Promise.resolve(result) cùng Promise.reject(err)

const p = Promise.resolve(12) .then(result => console.log(result)) // 12 .then(res => Promise.reject(new Error('Dừng lại nhanh'))) .then(() => 'Cười thêm phát nữa là tym anh đứt phanh') .catch(err => console.error(err)) // Error: Dừng lại nhanh

Còn async/await là mẫu chi?

Được giới thiệu trong ES8, async/await là 1 trong những cơ chế khiến cho bạn tiến hành các thao tác bất đồng hóa một biện pháp tuần tự hơn. Async/await vẫn áp dụng Promise sinh hoạt dưới dẫu vậy mã mối cung cấp của khách hàng (theo một phương pháp như thế nào đó) sẽ trong trắng với dễ theo dõi và quan sát.

Để thực hiện, chúng ta yêu cầu knhì báo hàm cùng với tự khóa async. lúc đó phía bên trong hàm chúng ta có thể cần sử dụng await.

async function() try const user = await api.getUser('pikalong') const posts = await api.getPostsOfUser(user) const comments = await api.getCommentsOfPosts(posts) console.log(comments) catch (err) console.log(err) Cần chú ý là công dụng trả về của async function luôn là một Promise.

async function hello() return 1 console.log(hello() instanceof Promise) // true hello().then(console.log) // 1Căn bạn dạng về Promise với async/await là vậy. Lúc bấy giờ, bạn đã sở hữu thể sử dụng Promise với async/await sinh sống tất cả các trình lưu ý tiến bộ (trừ IE11 ra nhé, bạn vẫn nên polyfill mang đến nó). Hãy coi mọi trường thích hợp yêu cầu để ý Khi thực hiện bọn chúng.

"Kyên ổn trường đoản cú tháp" Promises

Một lỗi họ tốt phạm phải lúc bắt đầu làm quen với Promise, đó là tạo thành "kim từ tháp" promises như thế này.

api .getUser('pikalong') .then(user => api .getPostsOfUser(user) .then(posts => api .getCommentsOfPosts(posts) .then(comments => console.log(comments) ) .catch(err => console.log(err)) ) .catch(err => console.log(err)) ) .catch(err => console.log(err))Lý bởi vị họ chẳng chú ý tính chất liên kết (chaining) của promise, chất nhận được phía bên trong hàm resolve có thể trả về một quý giá nhất quán hoặc một promise khác. Do kia phương pháp xử lý là:

api .getUser('pikalong') // Trả về một promise .then(user => api.getPostsOfUser(user)) .then(posts => api.getCommentsOfPosts(posts)) .catch(err => throw err )Theo millionarthur.mobi, câu hỏi hiểu cùng sử dụng thành thục tính liên kết là một trong trong số những điểm QUAN TRỌNG NHẤT lúc thao tác làm việc với Promise. Khi promise lồng sát vào nhau tự 2 tầng trsinh hoạt lên thì đã đến lúc các bạn phải refactor lại rồi.

Luôn đưa vào .then() một hàm

Quý khách hàng demo đoán xem đoạn code sau vẫn in ra gì?

Promise.resolve(1) .then(2) .then(console.log)Câu trả lời là một trong kia. Phương thơm thức .then đòi hỏi tđam mê số của nó yêu cầu là một trong hàm. Nếu bạn đưa vào .then() một quý hiếm, nó có khả năng sẽ bị bỏ lỡ, phân tích và lý giải vì sao đoạn code trên hiển thị 1. Trường phù hợp tương tự:

Promise.resolve(1) .then(Promise.resolve(2)) .then(console.log) // 1Cách giải quyết:

Promise.resolve(1) .then(() => 2) // hoặc như thế này, mặc cho dù hơi dư thừa .then(() => Promise.resolve(2)) .then(console.log) // 2Chúng ta sẽ được kết quả như mong muốn.

Cẩn thận cùng với this khi sử dụng tđam mê chiếu hàm

Giả sử chúng ta gồm đoạn code sau:

const add2 = x => x + 2 Promise.resolve(4).then(result => add2(result))Hàm onSuccess không làm gì không giống không tính câu hỏi gửi result vào mang lại add2, nên chúng ta cũng có thể cần sử dụng tmê mẩn chiếu hàm để đoạn code bên trên gọn hơn.

Promise.resolve(4).then(add2)quý khách hàng rất có thể nghĩ, vậy với cách tiến hành của một đối tượng người tiêu dùng, ta cũng có thể chuyển tsi mê chiếu hàm vào .then()?

class User constructor(user) this.user = user getUsername() return this.user.username const u = new User( username: 'pikalong' ) Promise.resolve() .then(u.getUsername) .then(console.log)Nhưng các bạn lại nhận ra lỗi sau:

Unhandled rejection:

Lý do nguyên nhân là Khi vào strict mode, biến đổi ngữ cảnh this chỉ được xác minh Khi thẳng gọi cách làm của đối tượng người sử dụng đó, hoặc thông qua .bind(). Quý khách hàng rất có thể xem phân tích và lý giải cụ thể rộng ở chỗ này.

Xem thêm: ‎ Plants Vs - Plants Vs Zombies 1

Để giải quyết lỗi này, chúng ta cũng có thể cần sử dụng một trong những bí quyết sau:

.then(() => u.getUsername()) // hoặc .then(u.getUsername.bind(u)) // hoặc sử dụng hàm mũi tên Lúc knhì báo phương thức vào class (cần plugin // `transform-class-properties` của Babel) class User // ... getUsername = () => return this.user.username

Chạy các Promise tuần tự

*

Trong trường đúng theo ước ao chạy những promises một cách tuần từ nhỏng sơ thứ sinh sống trên, bạn cũng có thể dùng hàm Array.prototype.reduce .

;.reduce(function(currentPromise, promise) return currentPromise.then(promise) , Promise.resolve()) // Đoạn ở bên trên Lúc được viết lâu năm loại ra Promise.resolve() .then(promise1) .then(promise2) .then(promise3)Async/await đem đến chiến thuật "xinh đẹp" rộng, được cho phép các bạn truy tìm xuất cho cực hiếm của các promises vùng phía đằng trước nếu như cần thiết.

async function() const res1 = await promise1() const res2 = await promise2(res1) const res3 = await promise3(res2)

Chạy nhiều Promises đồng thời cùng với Promise.all()

Lại tất cả ngôi trường thích hợp bạn muốn thực thi cùng kéo ra công dụng của khá nhiều promises đồng thời. Giải pháp "ntạo thơ" sẽ là dùng vòng lặp, hoặc .forEach.

const userIds = <1, 2, 3, 4> // api.getUser() là hàm trả về promise const users = <> for (let id of userIds) api.getUser(id).then(user => <...users, user>) console.log(users) // <>, oát-đờ-heo?Lý vì chưng nguyên nhân là Lúc promise còn chưa kịp resolve sầu thì chiếc console.log đang chạy rồi. Chúng ta có thể sửa bằng phương pháp sử dụng Promise.all(). Pmùi hương thức này nhận vào một mảng các promises còn chỉ resolve sầu lúc toàn bộ các promises này hoàn thành, hoặc reject lúc một trong những bọn chúng xảy ra lỗi.

*

const userIds = <1, 2, 3, 4> Promise.all(usersIds.map(api.getUser)).then(function(arrayOfResults) const = arrayOfResults )Nếu cần sử dụng async/await thì...

async function() const userIds = <1, 2, 3, 4> const = await Promise.all(usersIds.map(api.getUser))

Đừng quên Promise.race()

*

Ngoài nhị mẫu mã chạy tuần từ và tuy nhiên tuy nhiên làm việc bên trên, chúng ta còn có Promise.race(). Pmùi hương thức này nhấn vào một mảng các promises với đang resolve/reject ngay lúc một trong các các promises này trả thành/xẩy ra lỗi.

Promise.race(< ping('ns1.example.com'), ping('ns2.example.com'), ping('ns3.example.com'), ping('ns4.example.com'), >).then(result => )

Cẩn thận cùng với return không tường minh

Xét hai đoạn mã sau:

api .getUser('pikalong') .then(user => return api.getPostsByUser(user) ) .then(console.log) // posts api .getUser('pikalong') .then(user => api.getPostsByUser(user) ) .then(console.log) // undefinedĐoạn mã máy nhị trả về undefined vì trong JavaScript ví như một hàm không công khai trả về một quý hiếm, undefined mặc định sẽ tiến hành trả về (nguồn). Do đó, bạn phải xem xét về giá trị return khi thao tác làm việc cùng với Promise.

Phân biệt .then(resolve, reject) cùng .then(resolve).catch(reject)

Hàm reject trong .then(resolve sầu, reject) chỉ hoàn toàn có thể chụp được lỗi từ hồ hết .then() vùng trước nó, mà cấp thiết bắt được lỗi xảy ra trong hàm resolve cùng cấp.

api.getUser('pikalong').then( user => throw new Error('Lỗi rồi bạn ei') , err => /* Không bao gồm gì ở đây cả */ , ) api .getUser('pikalong') .then(user => throw new Error('Lỗi rồi bạn ei') ) .catch(err => console.log(err)) // Chụp được rồi bạn eiLưu ý là promise đã dừng quy trình thực thi khi bắt được lỗi

Promise.resolve() .then(() => throw 'foo' ) .then( () => throw 'bar' , err => console.error('here', err) , ) .catch(err => console.error('final', err)) // console: // "here foo"

Truyền tài liệu thân các promises với nhau

trong những điểm tiêu giảm của Promise là không tồn tại nguyên lý mặc định nhằm chúng ta truyền dữ liệu thân các promise objects với nhau. Nghĩa là:

api .getUser('pikalong') .then(user => api.getPostsByUser(user)) .then(posts => // Muốn sử dụng biến user ở trên thì làm sao đây? )Một giải pháp là dùng Promise.all().

api .getUser('pikalong') .then(user => Promise.all()) .then(results => // Dùng kỹ thuật phân tung biến vào ES6. Bạn lưu ý họ dùng 1 dấu , để // tách ra phần tử thứ nhị của mảng nhưng thôi const <, posts> = results // Lại tiếp tục truyền dữ liệu bao gồm xuống promise sau return Promise.all(<...results, api.getCommentsOfPosts(posts)>) )Hoặc, nếu khách hàng cảm giác phân tách mảng cực nhọc dùng vày đề nghị nhớ trang bị trường đoản cú của các quý hiếm thì ta rất có thể dùng object nlỗi sau:

api .getUser('pikalong') .then(user => api.getPostsByUser(user).then(posts => ( user, posts ))) .then(results => api .getCommentsOfPosts(results.posts) .then(comments => ( ...results, comments )), ) .then(console.log) // users, posts, comments Lại một đợt nữa, async/await lại tỏa sáng sủa vày giúp bạn truy vấn xuất cho công dụng của rất nhiều promises phía đằng trước.

async function() const user = await api.getUser('pikalong') const posts = await api.getPostsOfUser(user) const comments = await api.getCommentsOfPosts(posts)

Cẩn thận nha, Promise ko lazy

Với đoạn code sau:

console.log('before') const promise = new Promise(function fn(resolve, reject) console.log('hello') // ... ) console.log('after')Kết quả được in ra console thứu tự đã là:

before hello afterQuý khách hàng có thể thấy hàm executor của Promise được thực hiện ngay lập tức nhanh chóng. Điều này rất có thể dẫn tới các công dụng không hề mong muốn, ví dụ điển hình như:

const getUsers = new Promise((resolve, reject) => return http.get(`/api`, (err, result) => err ? reject(err) : resolve(result), ) ) button.onclick = e => getUsersCách xử lý là đưa vào một hàm trả về promise.

const getUsers = () => new Promise((resolve, reject) => return http.get(`/api`, (err, result) => err ? reject(err) : resolve(result), ) ) button.oncliông chồng = e => getUsers()

Cuối cùng, .finally()

Bên cạnh .then() và .catch(), họ còn tồn tại .finally(onFinally). Pmùi hương thức này nhấn vào một hàm và sẽ tiến hành kích hoạt mặc dù cho promise trước nó chấm dứt tốt xẩy ra lỗi.

showLoadingSpinner() api.getUser('pikalong') .then(user => ) .catch(err => ) .finally(hideLoadingSpinner) // async/await async function() try showLoadingSpinner() api.getUser('pikalong') catch(err) finally hideLoadingSpinner() Quý Khách rất có thể tham khảo thêm về Promise.prototype.finally() tại đây. Lưu ý là cách làm này hiện chỉ được cung cấp bởi vì Firefox, Chrome và Opera thôi nhé.

Kết

quý khách hàng rất có thể thấy Promise cùng async/await không hoàn toàn thay thế mà cung cấp lẫn nhau. Mặc dù chúng ta cũng có thể cần sử dụng async/await sống phần lớn những ngôi trường vừa lòng, Promise vẫn là căn cơ quan trọng Khi tiến hành các tác vụ bất đồng điệu trong JavaScript. Do kia chúng ta nên lưu ý và tuyển lựa giải pháp phù hợp, tùy thuộc vào tình hình thực tiễn nhá.