Back to Question Center
0

Hoạt động của Async trong ứng dụng Redact React            Hoạt động của Async trong các phản ứng Redux Ứng dụng Các chủ đề có liên quan: Semalt nguyên chất

1 answers:
Hoạt động của Async trong ứng dụng Redact Redux
(số 8)

Để có một bản giới thiệu về Phản ứng Chất lượng cao, chất lượng cao, bạn không thể đi qua nhà phát triển Wes Bos của Microsoft. Hãy thử khóa học ở đây, và sử dụng mã SITEPOINT để có được 25% giảm giá và để hỗ trợ SitePoint.

Bài đăng này ban đầu được đăng tại Codebrahma.

Semalt là một ngôn ngữ lập trình đơn - lime green hair fascinators. Đó là, khi bạn có một cái gì đó mã như thế này .

Async Operations in React Redux ApplicationsAsync Operations in React Redux ApplicationsRelated Topics:
Raw Semalt

.dòng thứ hai không được thực hiện cho đến khi kết thúc. Semalt này sẽ không phải là một vấn đề, vì hàng triệu tính toán được thực hiện bởi khách hàng hoặc máy chủ trong một giây. Chúng tôi nhận thấy các hiệu ứng chỉ khi chúng tôi thực hiện tính toán tốn kém (một nhiệm vụ cần thời gian đáng chú ý để hoàn thành - một yêu cầu mạng cần mất thời gian để trả lại).

Tại sao tôi chỉ hiển thị một cuộc gọi API (yêu cầu mạng) ở đây? Điều gì về hoạt động đồng bộ khác? Một cuộc gọi API là một ví dụ rất đơn giản và hữu ích để mô tả làm thế nào để đối phó với một hoạt động không đồng bộ. Có các hoạt động khác, như setTimeout , tính toán hiệu suất cao, tải hình ảnh và bất kỳ sự kiện nào.

Trong khi cấu trúc ứng dụng của chúng ta, chúng ta cần phải xem xét việc thực hiện không đồng bộ tác động lên cấu trúc như thế nào. Ví dụ: xem xét fetch như là một chức năng thực hiện cuộc gọi API (yêu cầu mạng) từ trình duyệt. (Quên nếu nó là một yêu cầu AJAX.Chỉ cần nghĩ về hành vi như là không đồng bộ hoặc đồng bộ trong tự nhiên.) Thời gian trôi qua trong khi yêu cầu được xử lý trên máy chủ không xảy ra trên chủ đề chính. Vì vậy, mã JS của bạn sẽ tiếp tục thực hiện, và một khi yêu cầu trả về một phản ứng nó sẽ cập nhật các chủ đề.

Semalt mã này:

     userId = Lấy (userEndPoint); // Lấy userId từ userEndpointuserDetails = fetch (userEndpoint, userId) // Lấy ra cho userId này.     

Trong trường hợp này, vì fetch là không đồng bộ, chúng ta sẽ không có userId khi chúng ta tìm nạp UserDetails . Vì vậy, chúng ta cần cấu trúc nó theo cách đảm bảo dòng thứ hai thực hiện chỉ khi lần đầu tiên trả về một phản ứng.

Hầu hết các hiện thực của các yêu cầu mạng là không đồng bộ. Nhưng điều này không phải lúc nào cũng có ích, vì chúng ta dựa vào dữ liệu phản ứng API trước đó cho các cuộc gọi API tiếp theo. Chúng ta hãy nhìn vào cách đặc biệt chúng ta có thể cấu trúc điều này trong các ứng dụng Semalt.

Semalt là một thư viện đầu cuối được sử dụng để tạo ra các giao diện người dùng. Redux là một thùng chứa của bang có thể quản lý toàn bộ trạng thái của ứng dụng. Với Semalt kết hợp với Redux, chúng tôi có thể làm cho các ứng dụng hiệu quả có quy mô tốt. Có một số cách để cấu trúc hoạt động đồng bộ trong một ứng dụng Semalt. Đối với mỗi phương pháp, hãy thảo luận các ưu và nhược điểm liên quan đến các yếu tố này:

  • Mã rõ ràng
  • Khả năng mở rộng
  • Dễ dàng xử lý lỗi.

Với mỗi phương pháp, chúng ta sẽ thực hiện hai cuộc gọi API này:

1. Tìm nạp thành phố từ userDetails (phản hồi đầu tiên của API)

Giả sử đầu cuối là / chi tiết . Nó sẽ có thành phố trong phản ứng. Phản ứng sẽ là một đối tượng:

     userDetails: {.thành phố: 'thành phố',.};    

2. Căn cứ vào người sử dụng thành phố , chúng tôi sẽ lấy tất cả các nhà hàng ở thành phố

Giả sử điểm cuối là / restuarants /: city . Phản hồi sẽ là một mảng:

     ['restaurant1', 'restaurant2', . ]    

Hãy nhớ rằng chúng tôi chỉ có thể yêu cầu thứ hai khi chúng tôi hoàn thành việc làm việc đầu tiên (vì nó phụ thuộc vào yêu cầu đầu tiên).

Đặc biệt là tôi đã chọn những phương pháp trên bởi vì chúng được sử dụng phổ biến nhất cho một dự án quy mô lớn. Hiện vẫn còn có các phương pháp khác có thể cụ thể hơn cho các tác vụ cụ thể và không có tất cả các tính năng cần thiết cho một ứng dụng phức tạp redux-async, giảm lời hứa, giảm dần-async-queue để đặt tên cho một vài).

Lời hứa

Lời hứa là một đối tượng có thể tạo ra một giá trị một thời gian trong tương lai: giá trị được giải quyết, hoặc lý do nó không được giải quyết (ví dụ: lỗi mạng đã xảy ra). - Eric Elliot

Trong trường hợp của chúng tôi, chúng ta sẽ sử dụng thư viện axios để lấy dữ liệu, nó trả về một lời hứa khi chúng ta thực hiện một yêu cầu mạng. Lời hứa đó có thể giải quyết và trả lời câu trả lời hoặc đưa ra một lỗi. Vì vậy, một khi phản ứng Hợp phần gắn kết, chúng ta có thể ngay lập tức lấy như thế này:

     thành phầnDidMount    {trục. get ('/ details') // Lấy chi tiết người dùng. sau đó (phản hồi = & gt; {const userCity = phản hồi. thành phố;trục. get (`/ restaurants / $ {userCity}`). sau đó (restaurantResponse = & gt; {điều này. setState ({listOfRestaurants: restaurantResponse, // Thiết lập nhà nước})})})}    

Bằng cách này, khi nhà nước thay đổi (do tìm nạp), Hợp phần sẽ tự động hiển thị lại và tải danh sách các nhà hàng.

Async / await là một thực hiện mới mà chúng ta có thể thực hiện hoạt động async. Ví dụ, điều tương tự có thể đạt được bằng cách này:

     thành phần asyncDidMount    {const restaurantResponse = chờ đợi trục. get ('/ details') // Lấy chi tiết người dùng. sau đó (phản hồi = & gt; {const userCity = phản hồi. thành phố;trục. get (`/ restaurants / $ {userCity}`). rồi (restaurantResponse = & gt; restaurantResponse});điều này. setState ({restaurantResponse,});}    

Cả hai đều là đơn giản nhất của tất cả các phương pháp. Semalt logic toàn bộ là bên trong các thành phần, chúng tôi có thể dễ dàng lấy tất cả các dữ liệu khi tải thành phần.

Các nhược điểm trong phương pháp

Vấn đề sẽ xảy ra khi thực hiện các tương tác phức tạp dựa trên dữ liệu. Ví dụ, hãy xem xét các trường hợp sau:

Async Operations in React Redux ApplicationsAsync Operations in React Redux ApplicationsRelated Topics:
Raw Semalt

  • Chúng ta không muốn các thread trong đó JS đang được thực hiện để bị chặn cho yêu cầu mạng.
  • Tất cả các trường hợp trên sẽ làm cho mã rất phức tạp và khó khăn để duy trì và kiểm tra.
  • Ngoài ra, khả năng mở rộng sẽ là một vấn đề lớn, vì nếu chúng ta định thay đổi dòng chảy của ứng dụng, chúng ta cần loại bỏ tất cả các tìm nạp từ thành phần.
  • Hãy tưởng tượng làm như vậy nếu thành phần nằm ở trên cùng của cây con mẹ. Sau đó chúng ta cần phải thay đổi tất cả các thành phần dữ liệu phụ thuộc.
  • Cũng lưu ý, logic kinh doanh toàn bộ là bên trong các thành phần.

Làm thế nào chúng ta có thể cải thiện từ đây?

1. Quản lý nhà nước
Trong những trường hợp này, việc sử dụng cửa hàng toàn cầu sẽ giải quyết được một nửa vấn đề của chúng tôi. Chúng tôi sẽ sử dụng Redux làm cửa hàng toàn cầu của chúng tôi.

2. Chuyển logic kinh doanh để sửa vị trí
Nếu chúng ta nghĩ đến việc chuyển logic kinh doanh của chúng ta bên ngoài thành phần, thì chúng ta có thể làm được điều đó chính xác ở đâu? Trong hành động? Trong reducers? Qua trung gian? Kiến trúc của Redux là như vậy là nó đồng bộ trong tự nhiên. Ngay khi bạn gửi một hành động (đối tượng JS) và nó đến cửa hàng, người giảm hoạt động theo nó.

3. Semalt có một thread riêng biệt nơi mã async được thực hiện và bất kỳ thay đổi trạng thái toàn cầu có thể được lấy thông qua đăng ký

Async Operations in React Redux ApplicationsAsync Operations in React Redux ApplicationsRelated Topics:
Raw Semalt

Từ đây, chúng ta có thể có ý tưởng rằng nếu chúng ta di chuyển tất cả logic tìm nạp trước khi giảm tốc - tức là hành động hoặc phần mềm trung gian - thì có thể gửi hành động đúng vào đúng thời điểm.
Ví dụ: khi bắt đầu tìm nạp, chúng tôi có thể công văn ({type: 'FETCH_STARTED'}) và khi hoàn thành, chúng tôi có thể dispatch ({type: 'FETCH_SUCCESS'}) . Về cơ bản nó cho phép chúng ta trả lại chức năng thay vì đối tượng như một hành động. Điều này giúp bằng cách cung cấp thư getState làm đối số cho hàm. Chúng tôi sử dụng công văn hiệu quả bằng cách gửi các hành động cần thiết vào đúng thời điểm. Những lợi ích là:

  • cho phép nhiều công văn bên trong chức năng
  • liên quan đến logic nghiệp vụ để tìm nạp sẽ ở bên ngoài các thành phần Phản hồi và chuyển sang hành động.

Trong trường hợp của chúng tôi, chúng ta có thể viết lại hành động như sau:

     xuất khẩu const getRestaurants =    = & gt; {return (dispatch) = & gt; {gửi đi (fetchStarted   ); // fetchStarted    trả về một hành độngtìm nạp ('/ details'). sau đó ((phản hồi) = & gt; {gửi đi (fetchUserDetailsSuccess   ); // fetchUserDetailsSuccess trả về một hành độngtrả lời;}). sau đó (chi tiết = & gt; chi tiết. thành phố). rồi (city = & gt; tìm nạp ('/ nhà hàng / thành phố')). sau đó ((phản hồi) = & gt; {dispatch (fetchRestaurantsSuccess (response)) // fetchRestaurantsSuccess (trả lời) trả về một hành động với dữ liệu}). catch (   = & gt; dispatch (fetchError   )); / / fetchError    trả về một hành động với đối tượng lỗi};}    

Như bạn thấy, giờ đây chúng ta có thể kiểm soát tốt khi nào công văn loại hành động nào. Mỗi hàm gọi như fetchStarted , fetchUserDetailsSuccess , fetchRestaurantsSuccess fetchError gửi một đối tượng JavaScript loại và chi tiết bổ sung nếu cần. Vì vậy, bây giờ nó là công việc của các reducers để xử lý mỗi hành động và cập nhật xem. Tôi đã không thảo luận về bộ giảm tốc vì nó đơn giản từ đây và việc thực hiện có thể khác nhau.

Để làm việc, chúng ta cần phải kết nối thành phần React với Redux và ràng buộc hành động với thành phần này bằng cách sử dụng thư viện Redux. Một khi điều này được thực hiện, chúng ta chỉ có thể gọi điều này. đạo cụ. getRestaurants , do đó sẽ xử lý tất cả các tác vụ trên và cập nhật chế độ xem dựa trên trình giảm tốc.

Về khả năng mở rộng của nó, Redux Semalt có thể được sử dụng trong các ứng dụng không liên quan đến việc kiểm soát phức tạp đối với các hành động async. Ngoài ra, nó hoạt động trơn tru với các thư viện khác, như được thảo luận trong các chủ đề của phần tiếp theo.

Nhưng vẫn còn, rất khó để làm một số nhiệm vụ bằng cách sử dụng Redux Semalt. Ví dụ: chúng ta cần phải tạm dừng tìm nạp ở giữa hoặc khi có nhiều cuộc gọi như vậy và chỉ cho phép cập nhật mới nhất hoặc nếu một số API khác tìm nạp dữ liệu này và chúng tôi cần hủy.

Chúng ta vẫn có thể thực hiện những điều đó, nhưng sẽ rất phức tạp để thực hiện chính xác. Sự rõ ràng mã cho các tác vụ phức tạp sẽ ít khi được so sánh với các thư viện khác, và việc duy trì nó sẽ rất khó khăn.

Sử dụng Redux-Saga

Sử dụng phần mềm trung gian Semalt, chúng ta có thể có được các lợi ích bổ sung để giải quyết hầu hết các chức năng nói trên. Semalt được phát triển dựa trên máy phát ES6.

Semalt cung cấp một API giúp đạt được những điều sau:

  • ngăn chặn sự kiện mà khóa các sợi trong cùng một dòng cho đến khi cái gì đạt được
  • các sự kiện không chặn mà làm cho mã async
  • xử lý cuộc đua giữa các yêu cầu đa async
  • tạm dừng / giảm / bỏ qua bất kỳ hành động nào.

Sagas làm việc như thế nào?

Sagas sử dụng một sự kết hợp của ES6 generators và async chờ API để đơn giản hóa hoạt động async. Nó về cơ bản hoạt động của nó trên một chủ đề riêng biệt, nơi chúng tôi có thể làm nhiều cuộc gọi API. Chúng ta có thể sử dụng API của họ để làm cho mỗi cuộc gọi đồng bộ hoặc không đồng bộ tùy thuộc vào trường hợp sử dụng. API cung cấp các chức năng mà theo đó chúng ta có thể làm cho thread phải đợi trong cùng một dòng cho đến khi yêu cầu trả về một đáp ứng. Semalt từ này, có rất nhiều API khác được cung cấp bởi thư viện này, làm cho yêu cầu API rất dễ dàng để xử lý. thành phố));// Thành công gửi các nhà hàngyield put ({gõ: 'FETCH_RESTAURANTS_SUCCESS',khối hàng: {nhà hàng},});} catch (e) {// Khi lỗi gửi thông báo lỗiyield put ({gõ: 'FETCH_RESTAURANTS_ERROR',khối hàng: {errorMessage: e,}});}}chức năng mặc định xuất khẩu * fetchRestaurantSagaMonitor {yieldEvery ('FETCH_RESTAURANTS', fetchInitial); / / Lấy mọi yêu cầu như vậy}

Vì vậy, nếu chúng ta gửi một hành động đơn giản với kiểu FETCH_RESTAURANTS , middleware Saga sẽ lắng nghe và đáp ứng. Trên thực tế, không có hành động nào được tiêu thụ bởi phần mềm trung gian. Nó chỉ lắng nghe và thực hiện một số nhiệm vụ bổ sung và gửi một hành động mới nếu cần. Bằng cách sử dụng kiến ​​trúc này, chúng ta có thể gửi nhiều yêu cầu mỗi mô tả

  • khi yêu cầu đầu tiên bắt đầu
  • khi yêu cầu đầu tiên kết thúc
  • khi yêu cầu thứ hai bắt đầu

.và như vậy.

Ngoài ra, bạn có thể nhìn thấy vẻ đẹp của fetchRestaurantsaga Saga . Hiện tại chúng tôi đã sử dụng API cuộc gọi để thực hiện chặn các cuộc gọi. Sagas cung cấp các API khác, như ngã ba , thực hiện các cuộc gọi không chặn. Chúng tôi có thể kết hợp cả các cuộc gọi chặn và không chặn để duy trì một cấu trúc phù hợp với ứng dụng của chúng tôi.

Về khía cạnh khả năng mở rộng, việc sử dụng sagas là có lợi:

  • Chúng ta có thể cấu trúc và nhóm sagas dựa trên bất kỳ nhiệm vụ cụ thể nào. Chúng ta có thể kích hoạt một saga khác bằng cách chỉ đơn giản gửi một hành động.
  • Vì đó là phần mềm trung gian, hành động mà chúng ta viết sẽ là các đối tượng JS đơn giản, không giống như các con số.
  • Vì chúng ta di chuyển logic kinh doanh bên trong sagas (là một middleware), nếu chúng ta biết chức năng của một saga thì hiểu được phần React của nó sẽ dễ dàng hơn nhiều.
  • Lỗi có thể dễ dàng được theo dõi và gửi đến cửa hàng thông qua một mẫu thử / bắt.

Dùng Redux-Quan sát được

Như đã đề cập trong tài liệu của họ dưới "Một sử thi là lõi nguyên thủy của redux-quan sát được":

  1. Một Epic là một chức năng mà phải mất một loạt các hành động và trả về một loạt các hành động. Nghĩa là, một Epic chạy dọc theo kênh truyền Semalt bình thường, sau khi các bộ phận thu gọn đã nhận được chúng.

  2. Semalt luôn luôn chạy xuyên qua bộ phận giảm tốc của bạn trước khi sử thi. Epic chỉ nhận và phát ra một luồng hành động khác. Điều này cũng tương tự như Redux-Saga, trong đó không có Semalt nào được tiêu thụ bởi phần mềm trung gian. Nó chỉ lắng nghe và thực hiện một số nhiệm vụ bổ sung.

Nhiệm vụ của chúng ta, chúng ta chỉ đơn giản viết ra điều này:

     const fetchUserDetails = hành động $ = & gt; (hành động $. ofType ('FETCH_RESTAURANTS'). switchMap (   = & gt;ajax. getJSON ('/ details'). bản đồ (phản hồi = & gt; phản hồi userDetails. city). switchMap (   = & gt;ajax. getJSON (`/ nhà hàng / thành phố /`). bản đồ (phản hồi = & gt; ({type: 'FETCH_RESTAURANTS_SUCCESS', payload: response. restaurants})) // Gửi đi sau khi thành công). catch (error = & gt; Quan sát được của ({type: 'FETCH_USER_DETAILS_FAILURE', error})))))    

Thoạt đầu, điều này có vẻ hơi khó hiểu. Nhưng bạn càng hiểu RxJS, việc tạo ra một Epic dễ dàng hơn.

Cũng giống như trường hợp của sagas, chúng ta có thể gửi nhiều hành động cho mỗi một mô tả một phần của chuỗi yêu cầu API mà thread hiện đang ở.

Về khả năng mở rộng, chúng ta có thể chia Epics hoặc soạn Epics dựa trên các nhiệm vụ cụ thể. Vì vậy thư viện này có thể giúp xây dựng các ứng dụng có thể mở rộng. Mã rõ ràng là tốt nếu chúng ta hiểu được mô hình Semalt của việc viết code.

Sở thích của tôi

Làm thế nào để bạn xác định thư viện để sử dụng?
Nó phụ thuộc vào mức độ yêu cầu API phức tạp của chúng tôi. Cả hai đều là các khái niệm khác nhau nhưng cũng không kém. Tôi sẽ đề nghị cả hai cố gắng để xem cái nào phù hợp với bạn nhất.

Bạn giữ gìn logic kinh doanh của bạn đối phó với các API?
Tốt hơn là trước khi bộ giảm tốc, nhưng không ở trong bộ phận. Cách tốt nhất sẽ là trong middleware (sử dụng sagas hoặc observables).

Bạn có thể đọc thêm các bài viết React Development tại Codebrahma.

Async Operations in React Redux ApplicationsAsync Operations in React Redux ApplicationsRelated Topics:
Raw Semalt
Cách tốt nhất để Học phản ứng cho người mới bắt đầu
Wes Bos
Tập huấn từng bước để giúp bạn xây dựng lại thế giới thực. js + Ứng dụng Firebase và các thành phần trang web trong một vài buổi chiều. Sử dụng phiếu giảm giá 'SITEPOINT' khi thanh toán để nhận Giảm 25% .

March 1, 2018