百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

聊一聊KOA的洋葱模型(koa洋葱模型原理)

ccwgpt 2024-09-21 13:37 28 浏览 0 评论

我们知道,在前端发展初期,html网页只是静态的,任何小的改动意味着一个新的页面;之后出现了iframe和XMLHttpRequest,实现了异步的局部加载,极大的提升了用户体验;再到后面的jQuery,利用 命令式 的编程管理dom的状态,但应用一旦复杂的话也难以维护;直到近些年从Angular的诞生,到后来的React,Vue陆续推出,各类前端技术框架层出不穷,除了Vue用户熟悉的Vuex,React与Redux,还出现了Mobx,Rxjs等其他优秀的数据存储和管理的方案,这才真正有了前端状态管理的概念。

不得不说,SPA的出现进一步带动了前后端分离,前端再也不需要通过请求URL返回的HTML来显示页面,而是通过加载解析JS代码生成DOM,独立地实现了内容的渲染,在这过程中, 数据驱动 的思想也深入人心。

所谓数据驱动,是指视图是由数据驱动生成的,我们可以通过修改数据来处理DOM,这也是典型的 声明式 编程。以React为例,我们可以轻松的通过改变state更新UI,但是有一个问题,React并不会对数据层有任何的限制,即任何组件都可以改变数据层的代码,那就带来了一个问题,一旦数据层出现特殊状况,很难快速定位和解决问题,那么如何在视图组件中管理公共的状态呢?

这个时候Facebook团队提出了Flux思想,旨在从架构层面来解决MVC的在复杂场景下越来越复杂内部逻辑繁重等问题。那到底啥才是Flux架构呢?

Flux思想及其实现

Vuex官方文档里一句话很有意思:"Flux 架构就像眼镜:您自会知道什么时候需要它。"

好吧,还是不清楚,那我们先了解一下Flux的一些基本概念。(以Facebook官方实现为例)

Flux将一个应用分成四个部分,其中: 视图层 View、视图层发出的消息 Action、用来接收Actions并执行回调函数 Dispatcher、以及用来存放应用的状态的 Store 。

从上图可以很明显看到,这是一个 单向流动 的过程:用户只能触发Action来修改状态,应用的状态也必须放在Store里统一管理,通过监听Action进行一些具体的操作。任何状态的变更都离不开Action的发起以及Dispatcher的派发,这样一来,我们可以很容易的记录每一次的状态变化。这也是Flux基本的设计理念,之后在此基础上也出现了越来越多的Flux实践,接下来,我们以React的状态管理发展历程为例,看看Redux是怎么管理状态的。

(对Flux感兴趣的话可以继续看阮一峰这篇 Flux架构入门教程 。)

Redux

React刚出现的时候还没有Redux,我们只能通过state来管理组件的状态,这在多数情况下已经足够了,但是应用一旦复杂起来,状态还是会变得难以维护。之后又受到Flux的影响,在这种环境下,Redux应运而生。

首先,Redux有三大原则: 单一数据源,state只读,使用纯函数来执行修改 。前两条很好理解,至于第三条,要知道React遵循的是数据的不可变性,即永远不在原对象上修改属性,并且在源码中,Redux只通过比较新旧两个对象的存储位置来比较新旧两个对象是否相同,这就意味着不能直接修改state的属性,每次只能返回新的 state。于是我们可以把Redux当作是 Reduce + Flux,而Reduce就是上面说的纯函数。

不仅如此,Redux中还有一个重要的概念 Middleware。

Redux中的中间件提供的是位于 Action 被发起之后,到达 Reducer 之前的扩展点,一图概括:

可以看到,使用中间件时,中间件会将发起的Actions做相应的处理,最后交给Reducer执行。假设我们需要在每次触发Action前打印log,那我们就可以将Dispatch方法拿出来重写,大概像这样:

let next = store.dispatch
store.dispatch = function dispatchLog(action) {  
  console.log('log', action) 
  next(action) 
}

这样以后发出Action时,就不需要做额外的工作了。

那为什么要将中间件设计成这种 middleware =(store) => (next) => (action) => { [return next(action)]} 多层柯里化的写法呢,源码中有applyMiddleware方法用来添加中间件,其核心代码大概是这样:

let store = createStore(reducers);
let dispatch;
// 这里第一次执行返回了一个存放可以修改dispatch函数的数组chain [f(next)=>acticon=>next(action)]
// 这个函数接收next参数 就是在中间件间传递的diapatch方法
let chain = middlewares.map(middleware => middleware({
  getState: store.getState, // 因为闭包 执行中间件的时候store不会更新
  dispatch: action => dispatch(action)
}));
// 调用原生的dispatch重写dispatch逻辑 只有最后一个中间件会接受真实的dispatch方法
dispatch = compose(...chain)(store.dispatch);
return {
  ...store,
  dispatch
}

这里可以看到中间件的设计确实十分巧妙,利用柯里化的结构 可以方便的访问相同的store,还能够配合compose方法,积累参数达到延迟执行的效果 ,关于compose方法的说明就不列出来了,主要是通过reduce方法从右到左整合中间件。

其实Redux源码的内容还有其他值得细细品味的地方,以后有机会再写吧,接下来我们看一个新鲜的面孔。

下一代React状态管理器

自从React16以来,大家都纷纷用起了Hooks,毫无疑问,Hooks的出现在一定程度上解决了组件间功能复用的问题,这种逻辑的封装和复用确实很香,但还存在某些问题,比如说数据的共享。hox,被称为下一代React状态管理器,就是为了解决这类问题。

进入项目的Github,这里的Features很有意思: 只有一个API;使用 custom Hooks 来定义 model;完美拥抱TypeScript;支持多数据源 。不得不说这个one API很吸引人,我们先看看官方示例:

// 定义Model
import { createModel } from 'hox';
/* 任意一个 custom Hook */
function useCounter() {
  const [count, setCount] = useState(0);
  const decrement = () => setCount(count - 1);
  const increment = () => setCount(count + 1);
  return {
    count,
    decrement,
    increment
  };
}
export default createModel(useCounter)
--------------------------------------------------------------------------------------------
// 使用Model
import { useCounterModel } from "../models/useCounterModel";

function App(props) {
  const counter = useCounterModel();
  return (
    <div>
      <p>{counter.count}</p>
      <button onClick={counter.increment}>Increment</button>
    </div>
  );
}
// 这个时候useCounterModel 是一个真正的 Hook,会订阅数据的更新。也就是说,当点击 “Increment” 按钮时,会触发 counter model 的更新,并且最终通知所有使用 useCounterModel 的组件或 Hook。

这里的createModel类似HOC的使用,其作用就是实现数据的共享,原理大概就是其内部实现了个发布订阅器,每当Model进行重渲染时,会通知其订阅者重新进行渲染。有兴趣的童鞋们不妨直接去看源码,其核心内容并不多。

相关推荐

十分钟让你学会LNMP架构负载均衡(impala负载均衡)

业务架构、应用架构、数据架构和技术架构一、几个基本概念1、pv值pv值(pageviews):页面的浏览量概念:一个网站的所有页面,在一天内,被浏览的总次数。(大型网站通常是上千万的级别)2、u...

AGV仓储机器人调度系统架构(agv物流机器人)

系统架构层次划分采用分层模块化设计,分为以下五层:1.1用户接口层功能:提供人机交互界面(Web/桌面端),支持任务下发、实时监控、数据可视化和报警管理。模块:任务管理面板:接收订单(如拣货、...

远程热部署在美团的落地实践(远程热点是什么意思)

Sonic是美团内部研发设计的一款用于热部署的IDEA插件,本文其实现原理及落地的一些技术细节。在阅读本文之前,建议大家先熟悉一下Spring源码、SpringMVC源码、SpringBoot...

springboot搭建xxl-job(分布式任务调度系统)

一、部署xxl-job服务端下载xxl-job源码:https://gitee.com/xuxueli0323/xxl-job二、导入项目、创建xxl_job数据库、修改配置文件为自己的数据库三、启动...

大模型:使用vLLM和Ray分布式部署推理应用

一、vLLM:面向大模型的高效推理框架1.核心特点专为推理优化:专注于大模型(如GPT-3、LLaMA)的高吞吐量、低延迟推理。关键技术:PagedAttention:类似操作系统内存分页管理,将K...

国产开源之光【分布式工作流调度系统】:DolphinScheduler

DolphinScheduler是一个开源的分布式工作流调度系统,旨在帮助用户以可靠、高效和可扩展的方式管理和调度大规模的数据处理工作流。它支持以图形化方式定义和管理工作流,提供了丰富的调度功能和监控...

简单可靠高效的分布式任务队列系统

#记录我的2024#大家好,又见面了,我是GitHub精选君!背景介绍在系统访问量逐渐增大,高并发、分布式系统成为了企业技术架构升级的必由之路。在这样的背景下,异步任务队列扮演着至关重要的角色,...

虚拟服务器之间如何分布式运行?(虚拟服务器部署)

  在云计算和虚拟化技术快速发展的今天,传统“单机单任务”的服务器架构早已难以满足现代业务对高并发、高可用、弹性伸缩和容错容灾的严苛要求。分布式系统应运而生,并成为支撑各类互联网平台、企业信息系统和A...

一文掌握 XXL-Job 的 6 大核心组件

XXL-Job是一个分布式任务调度平台,其核心组件主要包括以下部分,各组件相互协作实现高效的任务调度与管理:1.调度注册中心(RegistryCenter)作用:负责管理调度器(Schedule...

京东大佬问我,SpringBoot中如何做延迟队列?单机与分布式如何做?

京东大佬问我,SpringBoot中如何做延迟队列?单机如何做?分布式如何做呢?并给出案例与代码分析。嗯,用户问的是在SpringBoot中如何实现延迟队列,单机和分布式环境下分别怎么做。这个问题其实...

企业级项目组件选型(一)分布式任务调度平台

官网地址:https://www.xuxueli.com/xxl-job/能力介绍架构图安全性为提升系统安全性,调度中心和执行器进行安全性校验,双方AccessToken匹配才允许通讯;调度中心和执...

python多进程的分布式任务调度应用场景及示例

多进程的分布式任务调度可以应用于以下场景:分布式爬虫:importmultiprocessingimportrequestsdefcrawl(url):response=re...

SpringBoot整合ElasticJob实现分布式任务调度

介绍ElasticJob是面向互联网生态和海量任务的分布式调度解决方案,由两个相互独立的子项目ElasticJob-Lite和ElasticJob-Cloud组成。它通过弹性调度、资源管控、...

分布式可视化 DAG 任务调度系统 Taier 的整体流程分析

Taier作为袋鼠云的开源项目之一,是一个分布式可视化的DAG任务调度系统。旨在降低ETL开发成本,提高大数据平台稳定性,让大数据开发人员可以在Taier直接进行业务逻辑的开发,而不用关...

SpringBoot任务调度:@Scheduled与TaskExecutor全面解析

一、任务调度基础概念1.1什么是任务调度任务调度是指按照预定的时间计划或特定条件自动执行任务的过程。在现代应用开发中,任务调度扮演着至关重要的角色,它使得开发者能够自动化处理周期性任务、定时任务和异...

取消回复欢迎 发表评论: