Một trong những tính năng thú vị nhất dành cho những nhà phát triển được giới thiệu cùng Javascripts ES6, đó là một loại function rất đặc biệt, gọi là Generator.
Trong javascript một khi function được thực thi thì nó sẽ được đảm bảo run-to-completion tức là những phần code khác không thể can thiệp, làm gián đoạn quá trình chạy của function đó. Tuy nhiên Generator không hành xử theo lẽ thông thường như thế, chút nữa chúng ta sẽ cùng phân tích kĩ hơn. Cho dù bạn có nhận ra hay không, chúng ta có thể luôn thừa nhận một điều khá cơ bản rằng : Khi một function bắt đầu chạy, nó sẽ chạy cho đến khi hoàn thành trước khi bất kì đoạn code khác nào được chạy tiếp theo.
Ví dụ:
Tại đây, vòng lặp for tốn khá nhiều thời gian để hoàn thành, nhưng hàm callback với câu lệnh console.log(..) không thể ngắt quãng function foo() khi mà nó đang chạy, vì thế nó bị kẹt ở cuối hàng đợt, và kiên nhẫn đợi cho đến lượt mình.
Điều gì sẽ xảy ra nếu foo () có thể bị gián đoạn? Liệu chăng điều đó sẽ phá hủy chương trình của chúng ta ?
Với Generator, chúng ta có một loại function khác biệt, có thể dừng lại giữa chừng, một hay nhiều lần, và được khôi phục lại sau đó, cho phép các đoạn code khác chạy trong thời gian bị tạm dừng này. Đặc biệt, không có gì có thể tạm dừng một Generator từ bên ngoài; nó tạm dừng chính nó khi đi qua một yield. Tuy nhiên, khi một Generator được dừng lại, nó sẽ không thể tự khôi phục lại. Cần phải có một điều khiển từ bên ngoài để khởi động lại nó.
Vì thế, cơ bản thì một hàm Generator có thể tạm dừng lại và được khởi động lại, bao nhiêu lần tùy ý. Trong thực tế, bạn có thể chỉ định một hàm tạo ra một vòng lặp vô hạn (như là while (true) {..}) chạy suốt không bao giờ kết thúc. Trong khi thông thường nó có vẻ điên rồ hay là một sai lầm ở một chương trình JS bình thường, với Generator lại hoàn toàn bình thường và đôi khi thực hiện chính xác những gì bạn muốn làm!
Quan trọng hơn nữa, việc dừng và khởi động này không chỉ là kiểm soát việc thực hiện của function, mà nó còn cho phép giao tiếp thông tin 2 chiều giữa trong và ngoài hàm Generator. Với các hàm bình thường, bạn sẽ có được các tham số ở đầu và một giá trị trả về ở cuối. Với Generator, bạn gửi tin nhắn ra với mỗi lần yield, và bạn nhận được phản hồi cho mỗi lần trở lại.
Lưu ý, dấu *
dùng để báo hiệu đây là kiểu hàm Generator.
yield__
được coi như một “biểu thức yield” (không phải câu lệnh) bỏi vì khi khởi động lại Generator, chúng ta sẽ gửi dữ liệu vào bên trong. Và bất cứ dữ liệu gì ta gửi sẽ là kết quả của biểu thức yield__
Ví dụ:
Biểu thức yield "foo"
sẽ gửi chuỗi “foo” ra ngoài và tạm dừng hàm generator tại thời điểm đó. Khi được khởi động lại, bất kì giá trị nào được gửi vào sẽ là kết quả của biểu thức, sau đó được cộng thêm 1, và gán vào biến x.
Chắc bạn có thể dễ dàng nhận ra sự giao tiếp 2 chiều ở đây. Bạn gửi giá trị “foo” ra ngoài, tạm dừng lại. Tại 1 thời điểm sau đó (có thể ngay lập tức, cũng có thể là 1 khoảng thời gian dài). Generator sẽ được khởi động lại và nhận về dữ liệu. Có thể coi từ khóa yield
như một kiểu request cho một giá trị.
Ok, đó là một số khái niệm cơ bản về Generator.
Bạn có thể tự hỏi rằng, những thứ này có thể giúp ích gì cho dự án của mình. Và tại đây thì cuộc vui mới thực sự bắt đầu !!
Một số liên quan đến:
Những câu hỏi đó, và nhiều hơn nữa, sẽ được khám phá trong bài viết tiếp theo.. Còn giờ xin được tạm biệt !!
Quick Links
Social Media