从 Redux 源码角度理解 Redux-thunk、Redux-promise、Redux-saga

Redux 是一个用于 JavaScript 应用程序的预测性状态容器,它可以让您的应用行为一致且易于测试。Redux 可以帮助您管理各种状态,并确保状态变更是可控的和可预测的。但是,Redux 自身只提供了最基本的 API,如 createStore()、dispatch() 和 getState()。为了扩展 Redux 并处理异步操作,社区开发了许多中间件,Redux-thunk、Redux-promise 和 Redux-saga 就是其中的代表。

在本文中,我们将深入研究这三个流行的 Redux 中间件,弄清楚它们的工作原理以及它们如何与 Redux 一起工作。同时,我们将从 Redux 源码的角度出发,逐步学习这些中间件的实现原理。

Redux-thunk

在 Redux-thunk 中间件诞生之前,处理异步操作的最基本方法是在 Action 中返回一个函数,而不是一个对象。这个函数的参数是 dispatch() 方法。

举个例子,我们在 Redux 中定义了一个 Action:

------ ----- --------- - -------- -- -
  ------ ---------- -- -
    ---------- ----- -------------- ---
    ------ -------------------
      ---------- -- -
        ---------- ----- --------------------- -------- ---- ---
      --
      ------------ -- -
        ---------- ----- ------------------- -------- ----- ---
      ---
  --
--

在上面的代码中,fetchUser() 返回了一个函数,这个函数接收 dispatch() 方法作为参数。这个函数会异步获取用户数据,并在获取数据成功或失败后分别调用 dispatch() 方法来分发相应的 Action。

这种模式称为 thunk:一个返回函数的函数。Redux-thunk 就是一个中间件,可以将这种模式嵌入到 Redux 中。

实现原理

Redux-thunk 本质上是一个函数,它的作用是将异步操作延迟到 Action Creator 中。当一个 Action Creator 返回一个函数时,Redux-thunk 会执行这个函数并传入 dispatch() 方法和 getState() 方法。这个函数会在内部执行异步操作,并在完成后调用 dispatch() 方法来分发相应的 Action。

----- ----- - -- --------- -------- -- -- ---- -- ------ -- -
  -- ------- ------ --- ----------- -
    ------ ---------------- ----------
  -
  ------ -------------
--

以上是 Redux-thunk 中间件的代码实现。它接收一个 store 对象,并返回一个函数,这个函数负责处理 Action。当 store.dispatch() 方法被调用时,这个函数会被调用,并先检查传入的 action 是否为函数。如果 action 是函数,thunk 中间件会立刻执行这个函数,并将 store.dispatch() 和 store.getState() 作为参数传入。

案例分析

假设我们有一个 todoList 应用,用户可以在应用中添加、完成、删除待办事项。每当用户进行这些操作时,我们需要在数据库中同步数据。

我们可以使用 Redux-thunk 捕获用户添加待办事项的操作,并在操作完成后调用 API 同步数据。

------ ----- ---- --------

------ ----- ------- - ------ -- ----- ---------- -- -
  ---------- ----- ------------------ ---
  --- -
    ----- ------------------- - ---- ---
    ---------- ----- ------------------- -------- - ---- - ---
  - ----- ------- -
    ---------- ----- ------------------- -------- - ----- - ---
  -
--

在上面的代码中,我们使用了 async 函数来处理异步操作,并在操作完成后调用 dispatch() 方法来分发相应的 Action。

需要注意的是,Redux-thunk 只是一种“手动”处理异步操作的方式,因此我们需要自己管理异步操作的状态。同时,由于异步 Action 及其对应的 reducer 可能会非常复杂,因此在处理异步操作时仍需要谨慎。

Redux-promise

Redux-promise 是另一个处理异步 Action 的 Redux 中间件。它在传递给 dispatch() 方法的 Action 中提供了一个序列化的 Promise。

这个 Promise 表示异步操作的结果,可以在 reducer 中进行处理。

实现原理

与 Redux-thunk 类似,Redux-promise 也是一个函数,它的作用是将 Promise 嵌入到 Redux 中。当一个 Action Creator 返回一个 Promise 时,Redux-promise 会等待这个 Promise 完成,并分发相应的 Action。

----- ------- - -- -------- -- -- ---- -- ------ -- -
  -- ------- ----------- --- ----------- -
    ------ ----------------------
  -
  ------ -------------
--

以上是 Redux-promise 中间件的代码实现,与 Redux-thunk 非常相似。当 store.dispatch() 方法被调用时,这个函数会被调用,并先检查传入的 action 是否为 Promise。如果 action 是 Promise,Redux-promise 中间件会立刻等待这个 Promise 完成,并将完成后的结果作为参数调用 dispatch() 方法进行 Action 分发。

案例分析

假设我们有一个 weather app 应用,我们需要在异步获取天气数据后,将数据作为 payload 发送到 reducer 中。

我们可以使用 Redux-promise 在 Action 中返回一个 Promise,然后在 reducer 中处理异步 Action。

------ ----- ------------ - -- -- --
  ----- ----------------
  -------- ---------------------
---

在上面的代码中,我们定义了一个 Action Creator,它返回了一个包含 axios.get() 的 Promise。当这个 Promise 完成后,Redux-promise 中间件会调用 dispatch() 方法来分发相应的 Action,并将完成的结果传递给 reducer。

比起 Redux-thunk,Redux-promise 更加简单,并且可以根据返回的 Promise 自动处理异步 Action。因此,与 Redux-thunk 不同,我们不需要在 Action Creator 自己处理异步操作,也不需要在 reducer 中额外的处理。但相应的,Redux-promise 的灵活性则变得比较有限。

Redux-saga

Redux-saga 是一个中间件,可以用于处理异步操作和副作用。相比之前的 Redux-thunk 和 Redux-promise,Redux-saga 提供了更为灵活和强大的解决方案。

Redux-saga 是一个基于 Generator 的库,允许我们使用类似同步代码的方式编写异步代码,并且允许我们在 Redux 应用程序中进行复杂的控制流程和较为轻松的测试。

实现原理

Redux-saga 允许我们使用 Generator 函数来编写 saga。saga 是一段代码,在 saga 中会监听特定的 action,一旦符合则会触发一些异步操作。

--------- --------------------- -
  --- -
    ----- ---- - ----- ------------------- -----------------------
    ----- ----- ----- --------------------- -------- - ---- - ---
  - ----- ------- -
    ----- ----- ----- ------------------- -------- - ----- - ---
  -
-

--------- -------- -
  ----- ----------------------- ---------------
-

在上面的代码中,我们定义了一个名为 fetchUserSaga 的 Generator 函数,用于处理 action 类型为 FETCH_USER 的异步操作。在 saga 中,我们使用 call() 方法来调用 api.fetchUser() 方法,该方法返回 Promise。如果 Promise 成功执行,则使用 put() 方法来分发 FETCH_USER_SUCCESS。

在 mySaga 中,我们使用 takeEvery() 方法来监听 FETCH_USER action,当收到匹配的 DialogflowAction 后使用 fork 来执行相应的 saga。

案例分析

假设我们有一个 gallery 应用,用户可以在应用中浏览相片。当用户选择相片时,应用会自动开始加载相应的数据。我们可以使用 Redux-saga 来处理这个过程,并在完成后将数据作为 payload 分发给 reducer。

--------- ------------------------ -
  --- -
    ----- ----- ----- ---------------------- ---
    ----- ----------- - ----- -------------------------- --------------------------
    ----- ----- ----- ----------------------------- -------- ----------- ---
  - ----- ------- -
    ----- ----- ----- --------------------------- -------- ----- ---
  -
-

--------- ----------------------- -
  ----- ------------------------------- ------------------
-

------ ------- --------- ---------- -
  ----- -----
    ------------------------
  ---
-

在上面的代码中,我们定义了一个 Generator 方法 fetchGalleryData 用于处理 FETCH_GALLERY_DATA action,当收到匹配的 action 时,我们使用 try/catch 代码块包裹整个异步操作代码。在代码块内部,我们使用 put() 方法来分发 LOADING_GALLERY_DATA action,告诉应用已开始加载数据,同时使用 call() 方法来等待 api.fetchGalleryData() 方法返回数据。

当 api.fetchGalleryData() 执行后,我们使用 put() 方法来分发 FETCH_GALLERY_DATA_SUCCESS action,并将 fetchGalleryData 的结果作为 payload 传递给 action。如果异常发生,则触发 FETCH_GALLERY_DATA_ERROR action,并提供错误信息。

与 Redux-thunk 和 Redux-promise 不同,Redux-saga 允许我们在应用程序中执行真正的异步操作。这个库不仅提供了灵活和强大的解决方案,而且可以更容易地进行测试和重构。

结论

在本文中,我们通过讨论 Redux-thunk、Redux-promise 和 Redux-saga,深入了解了使用中间件处理异步操作的方法。同时,我们也了解了这些中间件在 Redux 源码中的实现原理。

在实际开发中,我们可以根据业务场景选择不同的中间件,对于较为简单的异步操作,我们可以使用 Redux-thunk 或 Redux-promise,对于较为复杂的异步操作,我们可以使用 Redux-saga 来处理相关逻辑。在使用中间件时,我们也需要谨慎思考,确保异步操作的状态正确,以避免出现困难和错误。

来源:JavaScript中文网 ,转载请联系管理员! 本文地址:https://www.javascriptcn.com/post/670f77c65f5512810264abe8


猜你喜欢

  • 响应式设计的精华总结

    随着移动设备的普及,越来越多的用户习惯于用手机或平板电脑访问网站。因此,响应式设计已经成为现代网站的必要特性。本文将讲述响应式设计的核心思想,其定义和实现,以及如何在实际项目中应用它。

    10 天前
  • 在 Angular 应用中使用 i18n 的最佳实践

    在今天的全球化语境下,一个应用程序必须面向多语言受众。而 i18n(国际化)是解决这一问题的方法之一。本文将介绍 Angular 应用中使用 i18n 的最佳实践,包括如何配置 i18n,如何在代码中...

    10 天前
  • 如何使用 Fastify 处理 WebSocket 连接

    随着 Web 技术的发展,WebSocket 越来越受到前端开发者的关注。WebSocket 可以在浏览器和服务器之间建立实时、持久的双向通信连接,常常用于实时聊天、游戏等应用中。

    10 天前
  • 深入浅出:如何使用 Yoga 来操作 GraphQL

    GraphQL 是一种先进的数据查询语言,它提供了一种灵活、高效的方式来获取所需的数据。Yoga 是一个用于创建 GraphQL 服务器的库,它提供了丰富的工具和函数,帮助我们轻松地实现 GraphQ...

    10 天前
  • 如何解决 Headless CMS 模板渲染出错的问题

    在现代化的 Web 应用程序开发中,Headless CMS 已经成为了一个非常流行的解决方案,因为它可以提供非常灵活的内容管理方式。不过,使用 Headless CMS 进行页面渲染时,开发人员可能...

    10 天前
  • Vue.js 入门教程之如何搭建一个简单的 Vue.js 项目

    Vue.js 是一个流行的 JavaScript 框架,它被广泛应用于构建现代的 Web 应用程序。在本文中,我们将介绍如何搭建一个简单的 Vue.js 项目,并提供详细的指导和示例代码。

    10 天前
  • 使用 Socket.io 实现多人在线图像处理

    在现代 Web 开发中,实现多人协作功能已经成为了一种趋势。而 Socket.io 提供了一种 elegant 的方式来实现多人在线协作,其中一个应用场景便是图像处理。

    10 天前
  • 如何使用 PM2 进行 Node.js 应用的进程粘滞保持?

    在 Node.js 应用的开发过程中,大部分时候都需要考虑进程的保持以及负载均衡问题。其中进程粘滞保持是一个非常重要的问题,它可以确保请求始终由同一个进程处理。 在本文中,我们将介绍如何使用 PM2 ...

    10 天前
  • 如何优化 SASS 中的重复代码

    在编写前端项目时,我们通常会使用 CSS 预处理器(如 SASS)来简化我们的工作流程。SASS 提供了许多有用的功能,如变量、混合器和继承等,使我们的样式代码更具可读性、可维护性和重用性。

    10 天前
  • 如何使用 TypeScript 编写高效的 React Hooks

    在 React 开发中,Hooks 是一个非常常见且有用的技术,它可以帮助我们构建更加高效、可复用的组件。而当我们结合 TypeScript 来使用 React Hooks 时,能够使我们的代码更加健...

    10 天前
  • 如何处理 SPA 应用中的 404 错误,提升用户体验?

    SPA(Single Page Application)应用是目前前端技术中的热门技术之一。与传统的多页面应用不同,SPA 应用只有一个 HTML 页面,通过异步加载数据并且使用 JavaScript...

    10 天前
  • 无障碍视力障碍者如何优化网站内容

    在设计和开发网站时,我们不应该只关注那些没有视力障碍的人。随着人们对无障碍访问的需求不断增长,为视力障碍者提供优化的网站内容已经成为了一种必要性。本文将介绍一些无障碍网站设计的技术和最佳实践,让你的网...

    10 天前
  • Service Worker 引发的问题和解决方法

    随着 Service Worker 的发展,越来越多的网站正在使用它来加速页面加载,提高离线体验以及提高安全性。但是,使用 Service Worker 也会带来一些问题。

    10 天前
  • Git 性能优化 —— 优化代码仓库的质量

    Git 是目前非常流行的版本控制系统,它的高效性和强大的功能受到了广泛的认可。对于大型的开发团队来说,Git 的性能优化尤为重要。在这篇文章中,我们将探讨如何通过优化代码仓库的质量,提高 Git 的性...

    10 天前
  • 解决使用 ES7 中的 Array.prototype.copyWithin 方法存在的数组越界问题

    前言 copyWithin 方法是 ES6 以及更新版本中新加入的方法,用于在数组内部进行元素复制操作。这个方法非常实用,可以方便地将数组内的元素进行复制和移动操作,避免了手动进行遍历和拷贝的麻烦。

    10 天前
  • Redux 最佳实践写作指南

    Redux 是一款非常流行的 JavaScript 状态管理库,它为前端应用的复杂状态管理提供了一种简洁、可预测的解决方案。尽管 Redux 的使用已经相当普遍,但很多开发者仍然存在很多不熟练的使用方...

    10 天前
  • 响应式设计在 WordPress 中的实践

    随着移动设备的普及,越来越多的人使用手机或平板电脑浏览网页。因此,响应式设计已经成为现代网页设计的必要组成部分。在 WordPress 中实现响应式设计也变得越来越重要。

    10 天前
  • Angular 中使用 Interpolation 和 Property Binding 的最佳实践

    在 Angular 中,我们有很多不同的方式来将组件的属性值传递到模板中。其中两个主要的方法是 Interpolation 和 Property Binding。本文将探讨这两种方法的最佳实践,以及如...

    10 天前
  • Fastify 中优化日志记录的技巧

    在开发 Web 应用程序时,日志记录是非常重要的。它可以帮助我们跟踪应用程序的运行状况,并确保任何故障都能得到及时的诊断和解决。在 Fastify 中,日志记录可以非常简单并且高效,同时还能提供丰富的...

    10 天前
  • Koa 应用程序中的访问控制技术

    在开发 Web 应用程序时,访问控制是一个非常重要的问题。要保护敏感数据和功能,以及防止非法用户访问资源(例如,用户的账户信息),就必须实现一定的访问控制措施。Koa 是一个流行的 Node.js W...

    10 天前

相关推荐

    暂无文章