Sơ lược về cách sử dụng Fork và Spawn trong redux-saga

Sơ lược về cách sử dụng Fork và Spawn trong redux-saga

Như các bạn đã biết redux-saga là một trong những redux middleware được sử dụng rộng rãi trong các ứng dụng reactjs, nó giúp việc xử lý các side effect trở nên đơn giản và nhanh chóng hơn. Với việc sử dụng ES6 Generators function giúp cho việc viết code asynchronous dễ dàng, dễ đọc và dễ test hơn. Nói sơ đến đây thôi, các bạn có thể tìm hiểu chi tiết hơn về redux-saga tại trang chủ. Bài viết này mình sẽ sơ lược hai effects của saga là fork và spawn theo cách hiểu của mình. Hy vọng nhận được gạch đá từ mọi người để tích góp về xây nhà dần ạ 😂😂😂

Thằng redux-saga nó bảo là chúng ta có thể fork những cái task chạy background bằng 2 thằng effects là Fork và Spawn. Về cơ bản 2 thằng này đều có nhiệm vụ là xử lý các task side effect bằng cơ chế non-blocking nhưng nó khác nhau ở chỗ:

Fork (attached): Được sử dụng để tạo ra các task mà đính kèm trực tiếp đến cha của nó, nghĩa là nếu có bất kỳ một error nào xảy ra trong suốt 1 saga thì nó sẽ báo lên thằng cha và dừng saga đó. Và nếu bạn cancel cha của nó thì tất cả các task con trong đó sẽ bị cancel hết.

Spawn (detached): Dùng để tạo ra các task riêng biệt với thằng cha của nó, nghĩa là khi có 1 task nào đó lỗi thì cũng sẽ không ảnh hưởng gì tới thằng cha trực tiếp của nó. Ngược lại, nếu bạn cancel thằng cha thì các task con bên trong nó vẫn bình thường như không có gì xảy ra, khi nào bạn chỉ định là à thằng spawn A này dừng lại, thì spawn A sẽ dừng lại, đấy cơ bản là vậy đó các bạn.

Để hiểu rõ hơn tôi sẽ mô tả kèm với ví dụ sau đây, chứ nói như trên là tôi tôi đọc xong cũng chưa hiểu gì hết 😁😁😁. Chúng ta đến với ví dụ nào:

Tôi sẽ lấy ví dụ trên trang chủ của redux-saga để nói luôn cho các bạn

Cụ thể về Fork sẽ như vầy:

– Các bạn có thể thấy, ở đây chúng ta có call(fetchAll), thằng này nó sẽ kết thúc khi và chỉ khi cả 2 fork và các nội dung task trong body của nó được thực thi xong. Đi sâu hơn một tí, tôi sẽ nói rõ cách thức fetchAll nó chạy như thế nào.

– Đầu tiên là thằng task1 nó chạy, nhưng vì task1task2 là bất đồng bộ nên nó sẽ chạy song song cùng lúc, và vì là non-blocking nên nó sẽ chạy tiếp xuống delay(1000), thì thằng delay(1000) này nó sẽ phải đợi sau 1 giây thì fetchAll mới được gọi là kết thúc mặc dù task1, 2 có chạy xong trước 1s đi nữa. Mặt khác, nếu task 1, 2 thực thi tốn nhìu thời gian hơn 1s, ví dụ 2, 3s chẳng hạn, thì lúc này fetchAll vẫn sẽ phải đợi các task trong fork chạy xong mới kết thúc được mặc dù là cái delay nó đã xong 1s trước rồi.

– Các bạn có thể thấy ở đây, về cách thức hoạt động nó sẽ giống như tôi đã nói ở trên, nhưng giờ chúng ta giả sử task1 hoặc task2 có 1 thằng bị lỗi gì đó, do là effect fork nên nó sẽ thông báo lỗi lên ngay thằng cha của nó (là fetchAll đấy), bảo là “cha ơi, con bị bệnh rồi” chẳng hạn vậy đó quý vị 😂😂. Lúc này cha nó sẽ cancel hết tất cả các task còn lại mà không cần biết các task đó đang có trạng thái gì và thông báo lên thằng main, nên các bạn thấy try catch trong main không. Các bạn có thắc mắc vì sao mình không bắt error ngay trong fetchAll mà phải bắt trong main, cái đó thì thằng chính chủ nó nói vầy nè quý vị, để tôi dẫn lời vào cho:

Note we’re able to catch the error from call(fetchAll) inside main only because we’re using a blocking call. And that we can’t catch the error directly from fetchAll. This is a rule of thumb, you can’t catch errors from forked tasks. A failure in an attached fork will cause the forking parent to abort (Just like there is no way to catch an error inside a parallel Effect, only from outside by blocking on the parallel Effect).