PROMISE 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 chúng ta ơi, chớ cấp khiêu vũ lên chuyến tàu tốc hành async/await trong lúc chưa rành Promise, kẻo lại xẩy ra “va chạm lúc dồn dịch”, gây nên hậu quả không thể đoán trước, vì căn bản async/await vẫn cần sử dụng Promise ở bên dưới nhưng mà thôi.

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

hoidapthutuchaiquan.vn sẽ điểm đông đảo quan niệm căn phiên bản về Promise, mặt khác đối chiếu với async/await để thấy khi nào thì nên xài mặt hàng như thế nào nhé.

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

Promise là 1 trong những cơ chế vào JavaScript giúp cho bạn tiến hành những tác vụ bất nhất quán nhưng không rơi vào tình thế callbaông chồng hell hay pyramid of doom, là triệu chứng các hàm callback lồng sát vào nhau ở rất nhiều tầng. Các tác vụ bất đồng hóa có thể là gửi AJAX request, hotline hàm bên trong setTimeout, setInterval hoặc requestAnimationFrame, tuyệt thao tác làm việc với WebSocket hoặc Worker… Dưới đấy là một callbachồng hell điển hình 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 với mây mây... ) ))lấy ví dụ như trên Lúc được viết lại bằng Promise đã là:

api .getUser("pikalong") .then((user) => api.getPostsOfUser(user)) .then((posts) => api.getCommentsOfPosts(posts)) .catch((err) => throw err )Để tạo nên một promise object thì bạn cần sử dụng class Promise có sẵn vào trình phê duyệt như sau:

const p = new Promise( /* executor */ function (resolve sầu, reject) // Thực thi các tác vụ bất đồng hóa ở đây, cùng hotline `resolve(result)` lúc tác // vụ xong. Nếu xảy ra lỗi, Điện thoại tư vấn cho `reject(error)`. ,)Trong đó, executor là một trong những hàm gồm nhì tsi mê số:

resolve sầu là hàm sẽ được gọi Khi promise hoàn thànhreject là hàm sẽ tiến hành 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 sầu, reject) => // Gửi AJAX request http.get(`/users/$username`, (err, result) => // Nếu bao gồm lỗi phía bên trong callbaông xã, họ Điện thoại tư vấn mang lại hàm `reject()` if (err) return reject(err) // Ngược lại, cần sử dụng `resolve()` nhằm trả tài liệu về mang lại `.then()` resolve(result) ) )bởi thế api.getUser() vẫn trả về một promise object. Chúng ta rất có thể truy tìm xuất đến công dụng trả về bằng cách làm .then() nlỗi sau:

function onSuccess(user) console.log(user)function onError(err) console.error(error)api.getUser("pikalong").then(onSuccess, onError)Pmùi hương thức .then(onSuccess, onError) dấn vào nhị hàm: onSuccess được Call Khi promise hoàn thành và onError được call Khi gồm lỗi xảy ra. Bên vào tyêu thích số onSuccess chúng ta có thể trả về một quý giá đồng điệu, chẳng hạn như quý giá số, chuỗi, null, undefined, array tuyệt object; hoặc một promise object không giống. Các cực hiếm bất đồng nhất sẽ tiến hành bọc phía bên trong một Promise, được cho phép chúng ta kết nối (chaining) nhiều promises lại cùng nhau.

promise() .then(() => return "foo" ) .then((result1) => console.log(result1) // "foo" return anotherPromise() ) .then((result2) => console.log(result2)) // `result2` vẫn là tác dụng của anotherPromise() .catch((err) => )Trong ví dụ trên, các bạn thấy mang lại thủ tục .catch(). Phương thơm thức này chỉ là cú pháp bọc đường (syntactic sugar) của .then(null, onError) nhưng mà thôi. Chúng ta đã nói thêm về .catch() sinh sống bên dưới.

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

Có phần nhiều ngôi trường phù hợp chúng ta chỉ việc quấn một cực hiếm vào promise tốt tự động reject. Thay do cần sử dụng cú pháp new Promise() dài mẫu, bạn có thể cần sử dụng nhì phương thức tĩnh Promise.resolve(result) và 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 vạc nữa là tym anh đứt phanh") .catch((err) => console.error(err)) // Error: Dừng lại nhanh

Còn async/await là cái chi?

Được trình làng trong ES8, async/await là 1 cơ chế giúp cho bạn thực hiện các thao tác làm việc bất đồng điệu một phương pháp tuần tự rộng. Async/await vẫn thực hiện Promise làm việc bên dưới cơ mà mã mối cung cấp của doanh nghiệp (theo một phương pháp như thế nào đó) vẫn trong sáng và dễ dàng theo dõi.

Để thực hiện, bạn yêu cầu khai báo hàm với tự khóa async. Lúc đó phía bên trong hàm bạn cũng có thể 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 xem xét là công dụng trả về của async function vẫn là một Promise.

async function hello() return 1console.log(hello() instanceof Promise) // truehello().then(console.log) // 1Căn bạn dạng về Promise với async/await là vậy. Hiện giờ, bạn đã có thể sử dụng Promise với async/await sống toàn bộ những trình coi sóc văn minh (trừ IE11 ra nhé, bạn vẫn yêu cầu polyfill mang đến nó). Hãy xem phần lớn ngôi trường vừa lòng yêu cầu lưu ý Lúc áp dụng chúng.

“Klặng từ bỏ tháp” Promises

Một lỗi bọn họ tuyệt mắc phải Lúc mới có tác dụng quen thuộc cùng với Promise, đó là tạo thành “klặng từ bỏ 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ý vày vì chưng bọn họ không để ý đặc thù link (chaining) của promise, cho phép bên phía trong hàm resolve có thể trả về một quý giá đồng nhất hoặc một promise khác. Do đó bí quyết 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 hoidapthutuchaiquan.vn, vấn đề phát âm cùng thực hiện thuần thục tính links là một giữa những điểm QUAN TRỌNG NHẤT Lúc thao tác cùng với Promise. khi promise lồng vào nhau từ 2 tầng trsinh hoạt lên thì đã đến lúc bạn phải refactor lại rồi.

Luôn chuyển vào .then() một hàm

quý khách test đoán thù xem đoạn code sau đã in ra gì?

Promise.resolve(1).then(2).then(console.log)Câu vấn đáp là một trong những kia. Phương thơm thức .then yên cầu ttê mê số của chính nó buộc phải là một hàm. Nếu bạn đưa vào .then() một giá trị, nó sẽ ảnh hưởng làm lơ, giải thích vì sao đoạn code bên 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ư vậy này, tuy nhiên khá dư quá .then(() => Promise.resolve(2)) .then(console.log) // 2Chúng ta sẽ được tác dụng như ý.

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

Giả sử các bạn có đoạn code sau:

const add2 = (x) => x + 2Promise.resolve(4).then((result) => add2(result))Hàm onSuccess không làm cái gi không giống kế bên vấn đề chuyển result vào mang đến add2, buộc phải chúng ta cũng có thể dùng tđam mê chiếu hàm để đoạn code bên trên gọn hơn.

Promise.resolve(4).then(add2)Bạn hoàn toàn có thể nghĩ về, vậy với thủ tục của một đối tượng người sử dụng, ta cũng có thể gửi tham 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 chúng ta lại nhận thấy lỗi sau:

Unhandled rejection:

Lý vị là do Lúc trong strict mode, trở nên ngữ chình ảnh this chỉ được khẳng định khi trực tiếp điện thoại tư vấn cách thức của đối tượng người sử dụng đó, hoặc thông qua .bind(). quý khách có thể coi lý giải chi tiết rộng tại chỗ này.

Xem thêm: Art Director Là Gì - Art Director Làm Công Việc Gì

Để xử lý lỗi này, chúng ta có thể dùng một giữa những cách sau:

.then(() => u.getUsername())// hoặc.then(u.getUsername.bind(u))// hoặc sử dụng hàm mũi thương hiệu Lúc knhì báo phương thức vào class (nê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 hy vọng chạy các promises một giải pháp tuần từ như sơ đồ sinh hoạt bên trên, bạn có thể sử dụng hàm Array.prototype.reduce .

;.reduce(function (currentPromise, promise) return currentPromise.then(promise), Promise.resolve())// Đoạn ngơi nghỉ trên lúc được viết nhiều năm chiếc raPromise.resolve().then(promise1).then(promise2).then(promise3)Async/await đem đến giải pháp “xinc đẹp” hơn, cho phép bạn truy nã xuất cho quý hiếm của những promises vùng trước giả dụ quan trọng.

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

Chạy các Promises cùng lúc cùng với Promise.all()

Lại tất cả trường phù hợp bạn có nhu cầu thực hiện với kéo ra hiệu quả của rất nhiều promises cùng lúc. Giải pháp “ntạo thơ” đang là dùng vòng lặp, hoặc .forEach.

const userIds = <1, 2, 3, 4>// api.getUser() là hàm trả về promiseconst users = <>for (let id of userIds) api.getUser(id).then((user) => <...users, user>)console.log(users) // <>, oát-đờ-heo?Lý bởi vì là vì lúc promise chưa kịp resolve thì dòng console.log vẫn chạy rồi. Chúng ta rất có thể sửa bằng cách sử dụng Promise.all(). Pmùi hương thức này thừa nhận vào một mảng những promises còn chỉ resolve lúc toàn bộ các promises này chấm dứt, hoặc reject lúc 1 trong các 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ị dạng hình chạy tuần trường đoản cú và song tuy vậy ở bên trên, họ còn tồn tại Promise.race(). Phương thức này dìm vào một mảng các promises cùng vẫn resolve/reject ngay trong khi 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 với return ko tường minh

Xét nhị đoạn mã sau:

api .getUser("pikalong") .then((user) => return api.getPostsByUser(user) ) .then(console.log) // postsapi .getUser("pikalong") .then((user) => api.getPostsByUser(user) ) .then(console.log) // undefinedĐoạn mã thiết bị hai trả về undefined vày 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 kia, bạn phải chú ý về quý giá return Lúc làm việc với Promise.

Phân biệt .then(resolve, reject) với .then(resolve).catch(reject)

Hàm reject vào .then(resolve, reject) chỉ hoàn toàn có thể chụp được lỗi trường đoản cú phần đông .then() vùng phía đằng trước nó, cơ mà cần yếu bắt được lỗi xảy ra vào hàm resolve cùng cấp cho.

api.getUser("pikalong").then( (user) => throw new Error("Lỗi rồi các bạn ei") , (err) => /* Không có gì tại đây cả */ ,)api .getUser("pikalong") .then((user) => throw new Error("Lỗi rồi chúng ta ei") ) .catch((err) => console.log(err)) // Chụp được rồi bạn eiLưu ý là promise sẽ giới hạn quy trình thực thi Lúc 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 giữa các promises với nhau

Một trong những điểm tiêu giảm của Promise là không có phép tắc khoác định để chúng ta truyền tài liệu giữa các promise objects với nhau. Nghĩa là:

api .getUser("pikalong") .then((user) => api.getPostsByUser(user)) .then((posts) => // Muốn nắn thực hiện đổi mới user nghỉ ngơi bên trên thì làm sao đây? )Một cách là cần sử dụng Promise.all().

api .getUser("pikalong") .then((user) => Promise.all()) .then((results) => // Dùng chuyên môn phân rã đổi mới vào ES6. Quý Khách xem xét chúng ta sử dụng 1 vết , nhằm // tách bóc ra phần tử đồ vật nhị của mảng mà thôi const <, posts> = results // Lại tiếp tục truyền tài liệu bao hàm xuống promise sau return Promise.all(<...results, api.getCommentsOfPosts(posts)>) )Hoặc, nếu bạn cảm giác phân bóc tách mảng cực nhọc sử dụng vày yêu cầu ghi nhớ sản phẩm từ bỏ của những quý giá thì ta hoàn toàn có thể dùng object nhỏng 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 lan sáng vày giúp cho bạn truy xuất cho tác dụng của những promises phía 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 theo lần lượt sẽ là:

beforehelloafterquý khách có thể thấy hàm executor của Promise được thực thi ngay nhanh chóng. Điều này hoàn toàn có thể dẫn đến những hiệu quả không 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.oncliông chồng = (e) => getUsersCách giải quyết và xử lý là gửi 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 xã = (e) => getUsers()

Cuối cùng, .finally()

Bên cạnh .then() với .catch(), bọn họ còn có .finally(onFinally). Phương thức này thừa nhận vào một trong những hàm và sẽ tiến hành kích hoạt dù cho promise trước nó kết thúc hay xẩy ra lỗi.

showLoadingSpinner()api.getUser("pikalong") .then(user => ) .catch(err => ) .finally(hideLoadingSpinner)// async/awaitasync function() try showLoadingSpinner() api.getUser("pikalong") catch(err) finally hideLoadingSpinner() quý khách rất có thể đọc thêm về Promise.prototype.finally() ở chỗ này. Lưu ý là phương thức này hiện nay chỉ được hỗ trợ vị Firefox, Chrome với Opera thôi nhé.

Xem thêm: Route Là Gì Và Nó Hoạt Động Như Thế Nào? Route Là Gì

Kết luận

Quý khách hàng rất có thể thấy Promise với async/await ko hoàn toàn sửa chữa thay thế mà hỗ trợ lẫn nhau. Mặc cho dù bạn cũng có thể sử dụng async/await nghỉ ngơi phần nhiều các ngôi trường hợp, Promise vẫn chính là gốc rễ cần thiết Lúc xúc tiến các tác vụ bất nhất quán trong JavaScript. Do đó chúng ta nên để mắt tới và chắt lọc chiến thuật tương xứng, tùy thuộc theo tình hình thực tiễn nhá.