Giả sử bạn duy trì một thư viện hiển thị một hàm getData
. Người dùng của bạn gọi nó để lấy dữ liệu thực tế:
var output = getData();
Dữ liệu ẩn được lưu trong một tệp để bạn triển khai getData
bằng Node.js được tích hợp sẵn fs.readFileSync
. Rõ ràng là cả hai getData
và fs.readFileSync
đều là các chức năng đồng bộ. Một ngày nọ, bạn được yêu cầu chuyển nguồn dữ liệu cơ bản sang một repo chẳng hạn như MongoDB, chỉ có thể được truy cập không đồng bộ. Bạn cũng được yêu cầu tránh làm phiền người dùng của mình, getData
không thể thay đổi API để trả về đơn thuần là một lời hứa hoặc yêu cầu tham số gọi lại. Làm thế nào để bạn đáp ứng cả hai yêu cầu?
Hàm không đồng bộ sử dụng lời gọi lại / lời hứa là DNA của JavasSript và Node.js. Bất kỳ ứng dụng JS không tầm thường nào đều có thể thấm nhuần phong cách mã hóa này. Nhưng thực tế này có thể dễ dàng dẫn đến cái gọi là kim tự tháp gọi lại của sự diệt vong. Thậm chí tệ hơn, nếu bất kỳ mã nào trong bất kỳ trình gọi nào trong chuỗi cuộc gọi phụ thuộc vào kết quả của hàm không đồng bộ, thì những mã đó cũng phải được bao bọc trong hàm gọi lại, áp đặt một ràng buộc về kiểu mã hóa đối với người gọi. Đôi khi, tôi nhận thấy cần phải đóng gói một hàm không đồng bộ (thường được cung cấp trong thư viện của bên thứ 3) thành một hàm đồng bộ để tránh tính toán lại toàn cục. Tìm kiếm giải pháp về chủ đề này thường kết thúc với Node Fibershoặc các gói npm bắt nguồn từ nó. Nhưng Fibers chỉ không thể giải quyết được vấn đề mà tôi đang gặp phải. Ngay cả ví dụ được cung cấp bởi tác giả của Fibers cũng minh họa sự thiếu hụt:
...
Fiber(function() {
console.log('wait... ' + new Date);
sleep(1000);
console.log('ok... ' + new Date);
}).run();
console.log('back in main');
Sản lượng thực tế:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
Nếu chức năng Fiber thực sự biến chế độ ngủ của chức năng không đồng bộ thành đồng bộ, đầu ra sẽ là:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
back in main
Tôi đã tạo một ví dụ đơn giản khác trong JSFiddle và tìm kiếm mã để mang lại đầu ra mong đợi. Tôi sẽ chấp nhận một giải pháp chỉ hoạt động trong Node.js vì vậy bạn có thể thoải mái yêu cầu bất kỳ gói npm nào mặc dù không hoạt động trong JSFiddle.