- vừa được xem lúc

Thoát khỏi địa ngục Callback: Bí quyết viết JavaScript bất đồng bộ sạch đẹp

0 0 3

Người đăng: Vũ Tuấn

Theo Viblo Asia

Nếu bạn đã làm việc với JavaScript trong một khoảng thời gian đáng kể, bạn có thể đã gặp phải "địa ngục callback" - mớ hỗn độn rối rắm của các callback lồng nhau khiến code của bạn khó đọc và khó bảo trì hơn. Nhưng đây là tin tốt: với các công cụ và mẫu phù hợp, bạn hoàn toàn có thể tránh được địa ngục callback và viết code bất đồng bộ sạch sẽ, hiệu quả. Chúng ta hãy cùng khám phá cách làm.

Promises: Bước đầu tiên cho code bất đồng bộ sạch sẽ

Promises là một cách có cấu trúc hơn để xử lý các hoạt động bất đồng bộ trong JavaScript và chúng giúp loại bỏ các callback lồng nhau sâu. Thay vì truyền các hàm làm đối số và lồng chúng, Promises cho phép bạn xâu chuỗi các hoạt động với các phương thức .then() và .catch(). Điều này giữ cho code tuyến tính và dễ theo dõi hơn nhiều.

VD:

// Callback hell example:
doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log(finalResult); }); });
}); // Using Promises:
doSomething() .then(result => doSomethingElse(result)) .then(newResult => doThirdThing(newResult)) .then(finalResult => console.log(finalResult)) .catch(error => console.error(error));

Trong cách tiếp cận dựa trên Promise này, mỗi bước theo sau bước trước theo một cách tuyến tính rõ ràng, giúp dễ dàng theo dõi luồng của code và gỡ lỗi nếu cần.

Async/Await: Giải pháp hiện đại

Mặc dù Promises rất tốt để dọn dẹp các callback lồng nhau, nhưng chúng vẫn có thể cảm thấy cồng kềnh khi xử lý nhiều hành động bất đồng bộ. Hãy đến với async và await. Các tính năng JavaScript hiện đại này cho phép bạn viết code bất đồng bộ trông gần giống như code đồng bộ, cải thiện khả năng đọc và bảo trì.

VD:

async function handleAsyncTasks() { try { const result = await doSomething(); const newResult = await doSomethingElse(result); const finalResult = await doThirdThing(newResult); console.log(finalResult); } catch (error) { console.error('Error:', error); }
} handleAsyncTasks();

Với async/await, bạn có thể xử lý Promises theo cách trực quan hơn nhiều, đặc biệt là đối với các nhà phát triển quen viết code đồng bộ. Nó loại bỏ nhu cầu xâu chuỗi .then() và giữ cho code của bạn trông đơn giản, từ trên xuống dưới.

Chia nhỏ các nhiệm vụ lớn thành các chức năng nhỏ

Một kỹ thuật mạnh mẽ khác để tránh địa ngục callback là chia các nhiệm vụ lớn, phức tạp thành các hàm nhỏ hơn, có thể tái sử dụng. Cách tiếp cận theo mô-đun này không chỉ cải thiện khả năng đọc mà còn giúp code của bạn dễ gỡ lỗi và bảo trì hơn.

Ví dụ: nếu bạn cần tìm nạp dữ liệu từ API và xử lý nó, thay vì viết mọi thứ trong một hàm lớn, bạn có thể chia nhỏ nó:

async function fetchData() { const response = await fetch('https://api.example.com/data'); return await response.json();
} async function processData(data) { // Process your data here return data.map(item => item.name);
} async function main() { try { const data = await fetchData(); const processedData = await processData(data); console.log('Processed Data:', processedData); } catch (error) { console.error('An error occurred:', error); }
} main();

Bằng cách tách các mối quan tâm của việc tìm nạp và xử lý dữ liệu thành các hàm riêng, code của bạn trở nên dễ đọc và bảo trì hơn nhiều.

Xử lý lỗi một cách khéo léo

Một thách thức lớn với code bất đồng bộ là xử lý lỗi. Trong một cấu trúc callback lồng nhau sâu, việc bắt và xử lý lỗi đúng cách có thể rất khó khăn. Với Promises, bạn có thể xâu chuỗi .catch() vào cuối các hoạt động của mình. Tuy nhiên, async/await kết hợp với các khối try-catch cung cấp một cách tự nhiên và dễ đọc hơn để xử lý lỗi.

VD:

async function riskyOperation() { try { const result = await someAsyncTask(); console.log('Result:', result); } catch (error) { console.error('Something went wrong:', error); }
} riskyOperation();

Theo cách này, bạn có thể bắt lỗi trong một phần cụ thể của code bất đồng bộ, giữ cho nó rõ ràng và dễ quản lý, đồng thời đảm bảo không có lỗi nào bị bỏ sót.

Quản lý nhiều hoạt động bất đồng bộ

Đôi khi bạn cần quản lý nhiều hoạt động bất đồng bộ đồng thời. Mặc dù Promise.all() thường được sử dụng, nhưng nó dừng thực thi khi một Promise thất bại. Trong những trường hợp như vậy, Promise.allSettled() sẽ đến để giải cứu—nó chờ tất cả các Promises được giải quyết (hoặc thành công hoặc thất bại) và trả về kết quả của chúng.

VD:

const promise1 = Promise.resolve('First Promise');
const promise2 = Promise.reject('Failed Promise');
const promise3 = Promise.resolve('Third Promise'); Promise.allSettled([promise1, promise2, promise3]) .then(results => { results.forEach(result => { if (result.status === 'fulfilled') { console.log('Success:', result.value); } else { console.error('Error:', result.reason); } }); });

Sử dụng Web Workers cho các công việc nặng

Đối với các tác vụ sử dụng nhiều CPU, như xử lý hình ảnh hoặc xử lý dữ liệu, bản chất đơn luồng của JavaScript có thể khiến ứng dụng của bạn bị đóng băng. Đây là nơi Web Workers tỏa sáng—chúng cho phép bạn chạy các tác vụ trong nền mà không chặn luồng chính, giữ cho UI phản hồi.

VD:

// worker.js
self.onmessage = function(event) { const result = performHeavyTask(event.data); self.postMessage(result);
}; // main.js
const worker = new Worker('worker.js'); worker.onmessage = function(event) { console.log('Worker result:', event.data);
}; worker.postMessage(dataToProcess);

Bằng cách chuyển các tác vụ nặng sang Web Workers, luồng chính của bạn vẫn rảnh rỗi để xử lý các tương tác UI và các chức năng quan trọng khác, đảm bảo trải nghiệm người dùng mượt mà hơn.

Kết luận

Tránh địa ngục callback và viết JavaScript bất đồng bộ sạch hơn là làm cho code của bạn dễ đọc, dễ bảo trì và hiệu quả hơn. Cho dù bạn đang sử dụng Promises, async/await, mô-đun hóa code của bạn hay tận dụng Web Workers, mục tiêu là giống nhau: giữ cho code của bạn phẳng và có tổ chức. Khi bạn làm điều đó, bạn sẽ không chỉ cứu mình khỏi những cơn ác mộng gỡ lỗi mà còn viết code mà những người khác (hoặc thậm chí là chính bạn trong tương lai!) sẽ cảm ơn bạn.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Typescript - Sự khác nhau giữa Typescript và Javascript

Typescript là gì. TypeScript là một ngôn ngữ giúp cung cấp quy mô lớn hơn so với JavaScript.

0 0 528

- vừa được xem lúc

Bạn đã biết các tips này khi làm việc với chuỗi trong JavaScript chưa ?

Hi xin chào các bạn, tiếp tục chuỗi chủ đề về cái thằng JavaScript này, hôm nay mình sẽ giới thiệu cho các bạn một số thủ thuật hay ho khi làm việc với chuỗi trong JavaScript có thể bạn đã hoặc chưa từng dùng. Cụ thể như nào thì hãy cùng mình tìm hiểu trong bài viết này nhé (go).

0 0 437

- vừa được xem lúc

Một số phương thức với object trong Javascript

Trong Javascript có hỗ trợ các loại dữ liệu cơ bản là giống với hầu hết những ngôn ngữ lập trình khác. Bài viết này mình sẽ giới thiệu về Object và một số phương thức thường dùng với nó.

0 0 159

- vừa được xem lúc

Tìm hiểu về thư viện axios

Giới thiệu. Axios là gì? Axios là một thư viện HTTP Client dựa trên Promise.

0 0 149

- vừa được xem lúc

Imports và Exports trong JavaScript ES6

. Giới thiệu. ES6 cung cấp cho chúng ta import (nhập), export (xuất) các functions, biến từ module này sang module khác và sử dụng nó trong các file khác.

0 0 113

- vừa được xem lúc

Bài toán đọc số thành chữ (phần 2) - Hoàn chỉnh chương trình dưới 100 dòng code

Tiếp tục bài viết còn dang dở ở phần trước Phân tích bài toán đọc số thành chữ (phần 1) - Phân tích đề và những mảnh ghép đầu tiên. Bạn nào chưa đọc thì có thể xem ở link trên trước nhé.

0 0 249