Lâu rồi chưa viết bài về kỹ thuật nên hôm nay viết bài để dân tình biết là mình vẫn còn code nhé
Kỳ này, chúng ta sẽ tìm hiểu về async/await, một cặp từ khóa rất bá đạo trong JavaScript chuẩn ES2017. Biết cách sử dụng async/await sẽ giúp ta viết code ngắn gọn, hiệu quả và dễ dàng hơn rất nhiều nhé
Retented architecture
JavaScript is the single-thread language, tức là chỉ có một luồng duy nhất để thực thi các dòng lệnh. Nếu chạy theo cơ chế đồng bộ [đồng bộ] thì khi thực hiện phức tạp tính toán, gọi yêu cầu AJAX tới máy chủ, gọi cơ sở dữ liệu [trong NodeJS], luồng này sẽ dừng để chờ, làm toàn bộ trình duyệt bị… treo
Để tránh điều này, hầu hết mã gọi yêu cầu AJAX hoặc cơ sở dữ liệu trong JavaScript đều chạy theo cơ chế bất đồng bộ [không đồng bộ]. Ban đầu, việc chạy mã không đồng bộ trong JavaScript được thực hiện nhờ gọi lại [như đoạn mã bên dưới]
Tệp này chứa văn bản Unicode hai chiều có thể được diễn giải hoặc biên dịch khác với nội dung hiển thị bên dưới. Để xem lại, hãy mở tệp trong trình chỉnh sửa hiển thị các ký tự Unicode bị ẩn.
Tìm hiểu thêm về ký tự Unicode hai chiều
Hiển thị ký tự ẩn
xem thô
ajax_callback. js
được lưu trữ với ❤ bởi GitHub
Tất nhiên, vì callback có một số nhược điểm như code long line, callback hell,… nên người ta tạo ra 1 pattern mới call là Promise
Các bạn nên xem lại kiến thức về Callback trong JavaScript và Promise trong JavaScript để có thể nắm rõ kiến thức phía dưới bài viết này nhé
Từ gọi lại, hứa đến Async/Await
Hứa sẽ giải quyết tốt các vấn đề của cuộc gọi lại. Mã trở nên dễ đọc, tách biệt và dễ bắt lỗi hơn
Tuy nhiên, dùng promise kép khi ta vẫn thấy hơi khó chịu vì phải truyền callback vào hàm then và catch. Code cũng sẽ hơi thừa và khó debug, vì toàn bộ hàm thì chỉ được tính là 1 câu lệnh nên không debug từng dòng được
May thay, in ES7 a allow color mang tên async/await đã ra đời. [Mình nghi 99% là phép màu này ăn cắp từ C# hay ho, vì C# đã có async/await từ thời của ông địa trường rồi cơ]
Vì vậy async/await có gì hay ho? .
Như ở phía trên, hàm findRandomImgPromise là hàm bất đồng bộ, trả về một Promise. Với từ khóa đang chờ, ta có thể coi hàm này là đồng bộ, câu lệnh phía sau chỉ được chạy sau khi hàm này trả về kết quả
Bấm Run Pen để xem demo nhé
Tại sao nên sử dụng async/await?
Như mình đã nói, async/await có một số điểm vượt trội so với lời hứa
- Code dễ đọc hơn rất rất nhiều, không cần thiết rồi bắt gì cả, cứ viết như code chạy tuần tự, sau đó dùng try/catch thông thường để bắt lỗi
- Viết vòng lặp qua từng phần tử trở nên vô cùng đơn giản, chỉ công việc chờ đợi trong mỗi vòng lặp
- Gỡ lỗi dễ dàng hơn nhiều, vì mỗi lần sử dụng await được tính là một dòng mã, do đó ta có thể đặt trình gỡ lỗi để gỡ lỗi từng dòng như bình thường
- Khi có lỗi, ngoại lệ sẽ chỉ ra lỗi ở dòng số nhiều chứ không phải chung chung là lời hứa chưa được giải quyết
- With promise or callback, việc kết hợp if/else hoặc retry với code không đồng bộ là cực hình vì ta phải viết code lòng vòng, rắc rối. Với async/await, công việc này vô cùng dễ dàng
Một vòng lặp demo khá thú vị bằng async đang chờ
Unupdate of async/await
Tất nhiên, async/await cũng có một số bất cập mà các bạn cần lưu ý khi sử dụng
- Cannot run on old browser. Nếu dự án yêu cầu phải chạy trên các trình duyệt cũ, bạn sẽ phải sử dụng Babel để transpiler code ra ES5 để chạy
- Khi chúng ta chờ đợi một lời hứa bị từ chối, JavaScript sẽ đưa ra một ngoại lệ. Do đó, nếu dùng async đang chờ mà quên try catch thì lâu lâu chúng ta sẽ bị… lỗi hoặc code tiếp tục chạy
- không đồng bộ và chờ đợi bắt buộc phải đi kèm với nhau. await only used in async function, if not will be syntax error. Do đó, async/await sẽ dần dần phát triển toàn bộ các hàm trong mã của bạn
Áp dụng async/await vào mã
Về bản chất, một hàm async sẽ trả về một lời hứa, tương ứng với Tác vụ trong C#. Làm như vậy, để có thể sử dụng async/await một cách hiệu quả, các bạn phải xác định rõ cơ chế làm việc của Promise nhé
Hiện tại phiên bản mới nhất của Chrome, Edge và Firefox đã hỗ trợ async/await, nếu dự án không bắt hỗ trợ các trình duyệt cũ, các bạn cứ thoải mái sử dụng async/await để code gọn đẹp hơn nhé.
Ngoài ra, nếu bạn sử dụng NodeJS, có thể sử dụng combo Promisify + Async/Await như sau
- Use Bluebird or util. promisify [Node 8 trở lên] để biến hàm callback của NodeJS thành Promise
- Use async/await to get results from this Promise
Kết quả
Bài viết kỳ này hơi phức tạp, lại cần nhiều kiến thức nền về JavaScript nên sẽ hơi khó hiểu
Các bạn cố gắng đọc lại 2,3 lần, xem lại các mẫu mã để hiểu nha. Nếu có thắc mắc hay có gì cần chia sẻ, các bạn cứ thoải mái comment nhé!