Node.js Generators & So sánh với lệnh gọi lại

Trong hướng dẫn này, chúng ta sẽ tìm hiểu về Generators và sự khác biệt của chúng với Callbacks

Máy phát điện là gì?

Generators đã trở nên khá nổi tiếng ở Node.js trong thời gian gần đây và đó có lẽ là do những gì họ có khả năng làm được.

  • Generatorlà các hàm thực thi có thể tạm dừng và tiếp tục ở thời điểm sau.
  • Generators rất hữu ích khi thực hiện các khái niệm như 'thực thi lười biếng'. Về cơ bản, điều này có nghĩa là bằng cách tạm dừng thực thi và tiếp tục theo ý muốn, chúng ta chỉ có thể lấy các giá trị khi cần.

Generators có 2 phương pháp chính dưới đây.

  1. Phương pháp năng suất – Phương thức lợi nhuận được gọi trong một hàm để tạm dừng việc thực thi hàm tại dòng cụ thể nơi phương thức lợi nhuận được gọi.
  2. Phương pháp tiếp theo – Phương thức này được gọi từ ứng dụng chính để tiếp tục thực thi hàm có phương thức lợi nhuận. Việc thực thi hàm sẽ tiếp tục cho đến phương thức lợi nhuận tiếp theo hoặc cho đến khi kết thúc phương thức.

Hãy cùng xem một ví dụ về cách sử dụng máy phát điện.

Trong ví dụ này, chúng ta sẽ có một hàm Add đơn giản để cộng 2 số, nhưng chúng ta sẽ tiếp tục dừng thực thi phương thức tại các thời điểm khác nhau để minh họa cách sử dụng trình tạo.

Node.js Generators

function* Add(x) {
   yield x + 1;
   var y = yield(null);
   y = 6
   return x + y;
}

var gen = Add(5);

gen.next();

gen.next(); 

Giải thích mã

  1. Bước đầu tiên là định nghĩa “hàm” máy phát điện của chúng ta. Lưu ý rằng điều này được thực hiện bằng cách thêm “*” vào từ khóa hàm. Sau đó, chúng ta định nghĩa một hàm có tên là Add lấy tham số là x.
  2. Từ khóa yield là từ khóa dành riêng cho generator. Điều này làm cho nó trở thành một cấu trúc mạnh mẽ để tạm dừng một hàm ở giữa bất kỳ thứ gì. Vì vậy, ở đây, việc thực thi hàm sẽ bị dừng lại cho đến khi chúng ta gọi hàm next(), điều này sẽ được thực hiện trong Bước 4. Tại thời điểm này, giá trị của x sẽ trở thành 6 và việc thực thi hàm sẽ bị dừng lại.
  3. Đây là nơi đầu tiên chúng ta gọi hàm tạo và gửi giá trị 5 đến hàm Add của chúng ta. Giá trị này sẽ được thay thế trong tham số x của hàm Add.
  4. Khi chúng ta gọi hàm next(), hàm Add() sẽ tiếp tục thực thi. Khi câu lệnh tiếp theo var y= energy(null) được thực thi, hàm Add() sẽ lại dừng thực thi.
  5. Bây giờ, sau khi gọi lại hàm next(), các câu lệnh tiếp theo sẽ chạy và giá trị kết hợp của x=5 và y=6 sẽ được cộng và trả về.

Gọi lại so với máy phát điện

Generators được sử dụng để giải quyết vấn đề được gọi là địa ngục gọi lại. Đôi khi các hàm gọi lại trở nên lồng nhau trong quá trình phát triển ứng dụng Node.js đến mức việc sử dụng các hàm gọi lại trở nên quá phức tạp.

Đây là nơi mà trình tạo hữu ích. Một trong những ví dụ phổ biến nhất về điều này là khi tạo các hàm hẹn giờ.

Chúng ta hãy xem ví dụ bên dưới để thấy trình tạo có thể hữu ích như thế nào so với lệnh gọi lại.

Ví dụ của chúng tôi sẽ chỉ tạo một hàm trì hoãn thời gian đơn giản. Sau đó, chúng tôi muốn gọi hàm này kết hợp độ trễ 1000, 2000 và 3000 ms.

Bước 1) Xác định chức năng gọi lại của chúng tôi bằng mã trễ thời gian cần thiết.

Cuộc gọi lại so với Generators

function Timedelay(ptime, callback) {

setTimeout(function() {
  
    callback("Pausing for " + ptime);
    
  }, time);
}

Giải thích mã

  1. Ở đây chúng ta đang tạo một hàm có tên Timedelay với tham số là ptime. Điều này sẽ gây ra độ trễ thời gian cần thiết mà chúng tôi muốn giới thiệu trong ứng dụng của mình.
  2. Bước tiếp theo là tạo một thông báo sẽ hiển thị cho người dùng nói rằng ứng dụng sẽ tạm dừng trong nhiều mili giây như vậy.

Bước 2) Bây giờ hãy xem mã nếu chúng ta đang kết hợp các lệnh gọi lại. Giả sử chúng ta muốn kết hợp các lệnh gọi lại dựa trên giá trị 1000, 2000 và 3000 mili giây, mã bên dưới cho biết cách chúng ta cần triển khai các lệnh gọi lại này bằng cách sử dụng lệnh gọi lại.

Cuộc gọi lại so với Generators

Timedelay(1000, function(message) {
  
  console.log(msg);
  Timedelay(2000, function(message) {
    
    console.log(msg);
    Timedelay(3000, function(message) {
      
      console.log(msg);
  })
  })
})

Giải thích mã

  1. Chúng tôi đang gọi Timedelay là một lệnh gọi lại với giá trị là 1000.
  2. Tiếp theo, chúng ta muốn gọi lại hàm Timedelay với giá trị là 2000.
  3. Cuối cùng, chúng ta muốn gọi lại hàm Timedelay với giá trị là 3000.

Từ đoạn mã trên, bạn có thể thấy nó trở nên lộn xộn hơn khi chúng ta muốn bắt đầu gọi hàm nhiều lần.

Bước 3) Bây giờ chúng ta hãy xem cách triển khai cùng một mã bằng cách sử dụng generators. Từ mã bên dưới, giờ bạn có thể thấy việc triển khai hàm Timedelay bằng generators đã trở nên đơn giản như thế nào.

Cuộc gọi lại so với Generators

function* Messages() {
  console,log(yield(Timedelay(1000, function(){})));
  console,log(yield(Timedelay(2000, function(){})));
  console,log(yield(Timedelay(3000, function(){})));
}

Giải thích mã

  1. Đầu tiên chúng ta sẽ định nghĩa một hàm tạo sẽ được sử dụng để gọi hàm Timedelay.
  2. Chúng tôi đang gọi hàm Yield cùng với hàm Timedelay với giá trị tham số là 1000.
  3. Sau đó, chúng tôi gọi hàm Yield cùng với hàm Timedelay với giá trị tham số là 2000.
  4. Cuối cùng, chúng ta gọi hàm Yield cùng với hàm Timedelay với giá trị tham số là 3000.

Tổng kết

Generators cũng có thể được sử dụng để giảm bớt các vấn đề với các lệnh gọi lại lồng nhau và hỗ trợ loại bỏ cái được gọi là địa ngục gọi lại. Generators được sử dụng để dừng quá trình xử lý của một hàm. Điều này được thực hiện bằng cách sử dụng phương thức 'yield' trong hàm không đồng bộ.