Computer >> Máy Tính >  >> Lập trình >> Javascript

Cách sử dụng Async và Await trong JavaScript

Được giới thiệu trong ES6, Promises cho phép bạn dễ dàng viết mã không đồng bộ mà không cần phải xử lý các hàm gọi lại khác nhau. Với Promises, bạn không cần phải lo lắng về các hàm gọi lại nhiều cấp vừa khó viết vừa khó duy trì.

Có một tính năng khác trong JavaScript giúp viết mã không đồng bộ dễ dàng hơn bằng cách sử dụng các hàm Promises:async / await. Chúng cho phép bạn viết mã trông có vẻ đồng bộ nhưng thực sự thực hiện các quy trình không đồng bộ.

Trong hướng dẫn này, chúng ta sẽ thảo luận về hàm async / await là gì và cách bạn có thể sử dụng nó trong mã của mình. Hãy bắt đầu!

Lời hứa:Người làm mới

Trước khi chúng ta bắt đầu nói về các hàm async / await, chúng ta cần tóm tắt lại Promises. Một lời hứa đại diện cho một hoạt động không đồng bộ. Nó cho mã của bạn biết rằng một hoạt động sẽ được thực hiện và nếu hoạt động thành công, một giá trị sẽ được trả về. Nếu không, lỗi sẽ được trả về phần còn lại của chương trình của bạn.

Lời hứa đại diện cho một giá trị mà không biết khi nào Lời hứa được tạo ra. Lời hứa chỉ là:một lời hứa rằng các giá trị trong tương lai sẽ được gửi trở lại mã của bạn. Vì Promise là tân ngữ nên phải viết hoa.

Hãy xem xét kịch bản này. Bạn cần truy xuất một tài nguyên từ một API. Quá trình này sẽ mất một hoặc hai giây để xử lý yêu cầu của bạn. Thay vì bắt người dùng đợi yêu cầu xử lý, bạn có thể chuyển mã của mình thành Lời hứa để phần còn lại của chương trình có thể tiếp tục chạy.

Điều này có nghĩa là bạn có thể tiếp tục hiển thị một phần giao diện người dùng của trang web trong khi dữ liệu đang được truy xuất. Ngay sau khi một giá trị được trả về, Lời hứa sẽ gửi nó đến chương trình chính của bạn.

Dưới đây là một ví dụ về Lời hứa:

81% người tham gia cho biết họ cảm thấy tự tin hơn về triển vọng công việc công nghệ của mình sau khi tham gia một cuộc thi đào tạo. Kết hợp với bootcamp ngay hôm nay.

Sinh viên tốt nghiệp bootcamp trung bình đã dành ít hơn sáu tháng để chuyển đổi nghề nghiệp, từ khi bắt đầu bootcamp đến khi tìm được công việc đầu tiên của họ.

let sendCookies = new Promise(resolve => {
	setTimeout(() => {
		resolve("Your cookies have been sent!");
	}, 1000);
});

sendCookies.then(data => {
	console.log(data);
})

Mã của chúng tôi trả về:Cookie của bạn đã được gửi! Khi chúng ta thực thi phương thức sendCookies.then (), Promise của chúng ta sẽ được khởi tạo. Chương trình của chúng tôi đợi 1.000 mili giây và sau đó gửi lại giá trị “Cookie của bạn đã được gửi!” vào chương trình chính của chúng tôi.

Cách sử dụng Async và Await

Trong một hàm async / await, một câu lệnh await chặn mã của bạn thực thi trong hàm async của nó cho đến khi một Promise được trả về. Chính vì lý do này mà các nhà phát triển thường nói rằng các hàm async / await trông có vẻ đồng bộ nhưng thực hiện các tác vụ không đồng bộ.

Hãy xem xét ví dụ sau:

function sendCookies() {
	return new Promise(resolve => {
		setTimeout(() => {
			resolve("Your cookies have been sent!");
		}, 1000);
	});
}

async function main() {
	const sendMessage = await sendCookies();
	console.log(sendMessage);
}

main();

Mã của chúng tôi trả về:Cookie của bạn đã được gửi! Phải mất 1.000 mili giây để hàm sendCookies () của chúng tôi trả về giá trị “Cookie của bạn đã được gửi”. Trong trường hợp này, chúng tôi đã khai báo một hàm không đồng bộ để mã của chúng tôi chờ một lời hứa giải quyết hoặc bị từ chối.

Từ khóa "async" cho mã của chúng tôi biết rằng chúng tôi muốn thực hiện một hoạt động không đồng bộ trong hàm của chúng tôi. Từ khóa “await” yêu cầu mã của chúng ta đợi sự trả lại của sendCookies () Promise trước khi nó tiếp tục thực thi chương trình của chúng ta.

Các hàm không đồng bộ luôn trả về một Lời hứa.

Sử dụng Async và Await với nhiều bước

Các hàm Async / await thường được sử dụng nhất khi có nhiều Promise mà bạn cần làm việc. Điều này đôi khi được gọi là chuỗi Promises. Điều này là do mã của bạn sẽ đợi Lời hứa được trả lại theo từng bước trước khi chuyển sang bước tiếp theo:

function processOrder()  {
	return new Promise(resolve => {
		setTimeout(() => {
			resolve("Your cookie order is being processed...");
		}, 1000);
	});
}

function sendCookies() {
	return new Promise(resolve => {
		setTimeout(() => {
			resolve("Your cookies have been sent!");
		}, 1000);
	});
}

async function main() {
	const processingMessage = await processOrder();
	console.log(sendMessage);

	const sendMessage = await sendCookies();
	console.log(sendMessage);
}

Mã của chúng tôi trả về:

Your cookie order is being processed…
Your cookies have been sent!

Mỗi bước mất 1.000 mili giây để hoàn thành. Hàm sendCookies () của chúng tôi không được thực thi cho đến khi trả về Promise từ hàm processOrder () của chúng tôi.

Biểu thức không đồng bộ

Có ba cách bạn có thể sử dụng hàm async / await.

Cách đầu tiên là cách tiếp cận mà chúng tôi đã chỉ ra trong các ví dụ cuối cùng của chúng tôi:thông qua khai báo các hàm. Trong các ví dụ của chúng tôi, chúng tôi đã khai báo các hàm trả về một Lời hứa, sau đó chúng tôi đã sử dụng các từ khóa “async” và “await” để thực thi các hàm đó.

Bạn cũng có thể khai báo một hàm không đồng bộ bằng cách sử dụng các hàm mũi tên:

const main = async () => {
	const sendMessage = await sendCookies();
	console.log(sendMessage);
}

Mã này trả về:Cookie của bạn đã được gửi đi! Nó giống như ví dụ đầu tiên của chúng tôi nhưng thay vì khai báo một hàm main (), chúng tôi đã sử dụng một hàm mũi tên.

Tương tự, bạn có thể sử dụng cú pháp biểu thức hàm:

const main = async function() {
	const sendMessage = await sendCookies();
	console.log(sendMessage);
}

Mã này trả về:Cookie của bạn đã được gửi đi! Như bạn có thể thấy, kết quả đầu ra một lần nữa giống nhau. Sự khác biệt duy nhất là cách chúng tôi đã khai báo chức năng của mình.

Trên thực tế, cú pháp này rất giống với ví dụ cuối cùng của chúng tôi. Chúng tôi vừa sử dụng từ khóa “function ()” thay vì sử dụng hàm mũi tên.

Không có cách tốt nhất để khai báo một hàm async / await. Tất cả phụ thuộc vào chương trình bạn đang viết và bạn thích cú pháp nào. Trong khi bạn có thể tranh luận rằng các hàm mũi tên là phương pháp ngắn gọn nhất, các cách khai báo hàm không đồng bộ / await có thể tốt hơn trong các trường hợp khác.

Xử lý các yêu cầu trên web bằng Async / Await

Một trong những cách sử dụng phổ biến nhất của hàm async / await là xử lý các yêu cầu web bằng API dựa trên Promise, chẳng hạn như fetch (). Bạn có thể đọc thêm về cách sử dụng hàm fetch () trong hướng dẫn tìm nạp JavaScript cho người mới bắt đầu của chúng tôi.

Hãy xem xét ví dụ này:

async function retrieveComments() {
	const res = await fetch('https://jsonplaceholder.typicode.com/comments');
	var comments = await res.json();

	comments = comments.map(comment => comment.name);

	console.log(comments);
}

retrieveComments();

Mã của chúng tôi trả về:

["id labore ex et quam laborum", "quo vero reiciendis velit similique earum" …]

Khi chúng tôi thực thi hàm getComments (), chúng tôi sử dụng từ khóa “await” để đợi câu lệnh fetch () của chúng tôi chạy. Điều này có nghĩa là phần còn lại của chương trình của chúng tôi không tiếp tục cho đến khi yêu cầu web của chúng tôi được xử lý. Điều này là do hàm fetch () trả về một Promise.

Khi một Promise được trả về bởi hàm fetch (), chúng tôi sẽ chuyển đổi giá trị mà nó đã trả về JSON. Sau đó, chúng tôi ánh xạ qua đối tượng để truy xuất danh sách tên của tất cả các nhận xét và in danh sách đó ra bảng điều khiển.

Cách xử lý lỗi

Ôi, tôi ước gì lỗi đó không xảy ra trong mã. Nhưng họ làm được và đó là điều mà các nhà phát triển chúng tôi phải lên kế hoạch. Trong một hàm không đồng bộ, việc xử lý lỗi được thực hiện đồng bộ bằng cách sử dụng câu lệnh try… catch. Hãy xem xét mã này:

async function retrieveCookies() {
	const res = await fetch('https://thisapidoesnotexist.app/cookies');
	var cookieNames = await res.json();

	cookieNames = cookieNames.map(cookie => cookie.name);

	resolve(cookieNames);
}

async function printCookies() {
	const cookies = await retrieveCookies();
	console.log(cookies);
}

printCookies().catch(res => console.log(res.message));

Mã của chúng tôi trả về:

NetworkError when attempting to fetch resource. While our code is functional, the API we are trying to access does not exist. This means that our Promise cannot return any data, so it instead returns a rejected Promise.

Trong ví dụ của chúng tôi, chúng tôi đã sử dụng câu lệnh .catch () để in ra lỗi được trả về bởi hàm của chúng tôi nếu một lỗi được trả về. Trong trường hợp này, chúng tôi sử dụng từ chối (‘Lỗi’) để cho mã của chúng tôi biết rằng đã phát sinh lỗi.

Nếu câu lệnh này được thực thi, câu lệnh .catch () của chúng tôi sẽ bắt đầu hoạt động và in ra lỗi đó.

Tương tự, các hàm không đồng bộ có thể mắc lỗi cú pháp:

async function retrieveCookies() {
	const res = await fetch('https://thisapidoesnotexist.app/cookies');
	var cookieNames = await res.json();

	cookieNames = cookieNames.map(cookie => cookie.name);

	resolve(cookieNames);
}

async function printCookies() {
	try {
		const cookies = await retrieveCookies();
		console.log(cookies);
	} catch(error) {
		console.log(error);
	}
}

printCookies();

Mã của chúng tôi trả về:NetworkError khi cố gắng tìm nạp tài nguyên. Trong ví dụ này, chúng tôi đã sử dụng câu lệnh try / catch để kiểm tra xem phương thức await của chúng tôi có trả về một Lời hứa thành công hay không. Một lần nữa, API của chúng tôi không hợp lệ, điều này khiến chương trình của chúng tôi từ chối Lời hứa của chúng tôi. Khi điều này xảy ra, câu lệnh “catch” trong khối try / catch của chúng tôi được thực thi, ghi lại lỗi của chúng tôi vào bảng điều khiển.

Kết luận

Các hàm async / await giúp bạn viết các hoạt động không đồng bộ trong mã của mình. Khi một hàm không đồng bộ được khai báo, bạn có thể sử dụng từ khóa “await” để đợi các hoạt động giải quyết. Từ khóa await phải được sử dụng với một hàm trả về một Lời hứa.

Bây giờ, bạn đã sẵn sàng để bắt đầu sử dụng các hàm JavaScript async / await như một chuyên gia!