导读:本期聚焦于小伙伴创作的《如何构建一个无依赖的、轻量级的JavaScript状态管理库?》,敬请观看详情。当项目里引入Redux或MobX后打包体积陡增,又觉得它们的概念太重,能不能用不到一百行代码自己写一个状态管理核心?本文从发布订阅原理出发,说明如何用纯JavaScript实现状态的集中存储、变更通知与按需订阅。我们会对比框架自带方案与自己实现的差异,给出避免重复渲染和内存泄漏的实操细节,并提供一个可直接用于生产环境的最小实现,帮助你在中小项目中彻底摆脱外部依赖。

在中小型前端项目里,引入庞大的状态管理框架往往带来不必要的体积和复杂度。通过原生JavaScript的发布订阅模式,我们可以自己实现一个无依赖、轻量且易扩展的状态管理库,核心代码甚至可以控制在百行以内。它只做三件事:集中存储状态、统一修改入口、通知订阅者。下面我们一步步拆开讲。

如何构建一个无依赖的、轻量级的JavaScript状态管理库?

一、核心原理:发布订阅模式

状态管理库的本质是一个中心化的数据存储,配合一个消息机制。当数据发生变化时,所有关心这部分数据的视图或逻辑都能收到通知并作出响应。这种机制在JavaScript里最基础的实现就是发布订阅(Publish-Subscribe)。

我们维护一个监听器列表,对外暴露subscribe方法用于注册回调,暴露setState方法用于修改状态并触发回调。为了避免外部直接篡改内部状态,状态对象应该通过闭包保护起来,只提供只读的getState

function createStore(initialState) {
  let state = initialState;
  const listeners = new Set();

  function getState() {
    return state;
  }

  function subscribe(listener) {
    listeners.add(listener);
    // 返回取消订阅函数
    return function unsubscribe() {
      listeners.delete(listener);
    };
  }

  function setState(partial) {
    const next = typeof partial === 'function'
      ? partial(state)
      : partial;
    state = Object.assign({}, state, next);
    listeners.forEach(function (fn) {
      fn(state);
    });
  }

  return { getState, subscribe, setState };
}

二、支持按需订阅与避免重复渲染

上面的基础版在状态任意字段变化时都会通知所有监听器,这在视图层容易造成重复渲染。我们可以让subscribe支持传入一个选择器函数,只在某些字段变化时才触发回调。

具体做法是订阅时保存上一次选出的片段,触发通知前用新状态计算出当前片段,通过浅比较判断是否需要调用回调。这样组件只关心自己用的数据,性能更好,也避免了无关更新。

function createStore(initialState) {
  let state = initialState;
  const entries = new Set();

  function getState() {
    return state;
  }

  function subscribe(selector, listener) {
    let prev = selector(state);
    const entry = {
      selector: selector,
      listener: listener,
      prev: prev
    };
    entries.add(entry);
    return function () {
      entries.delete(entry);
    };
  }

  function setState(partial) {
    const next = typeof partial === 'function'
      ? partial(state)
      : partial;
    state = Object.assign({}, state, next);
    entries.forEach(function (e) {
      const cur = e.selector(state);
      if (cur !== e.prev) {
        e.prev = cur;
        e.listener(cur, state);
      }
    });
  }

  return { getState, subscribe, setState };
}

三、与主流框架方案的对比

自己实现的库和Redux相比,缺少中间件、时间旅行调试等高级特性,但优势是零依赖、体积小、概念少。在不需要复杂副作用管理的后台系统、嵌入式页面中,这种轻量方案反而更容易维护。

和React的useState比,我们的库是跨组件共享的全局 store,不需要逐层传递 props。如果配合极少量的桥接代码,就能在任意框架中使用,不绑定技术栈。

方案依赖体积学习成本适用场景
Redux约 2KB 以上加中间件大型复杂应用
自研轻量库小于 1KB中小项目、嵌入式
框架内置 State随框架单组件或局部

四、内存泄漏与最佳实践

使用发布订阅最容易犯的错误是组件卸载后忘记取消订阅,导致监听器越积越多。因此subscribe必须返回取消函数,并在组件销毁生命周期里调用。上面的实现中我们已经返回了移除函数。

另一个实践是禁止外部直接修改getState拿到的对象。虽然我们返回的是同一引用,但良好的约定是所有变更走setState,这样变更可追踪。若更严格,可在getState里返回浅拷贝,不过会带来轻微性能损耗,可按需取舍。

// 在组件中使用示例
const store = createStore({ count: 0, name: 'test' });

const unsub = store.subscribe(
  function (s) { return s.count; },
  function (count) {
    console.log('count changed:', count);
  }
);

store.setState({ count: 1 });
unsub(); // 组件卸载时调用

五、完整最小实现

把前面的能力合并,就得到了一个无依赖的状态管理库。它支持全局状态、按需订阅、安全取消,可直接放进项目里使用,也可以继续扩展出中间件、批量更新等能力。

以下代码可直接保存为store.js引用,没有任何外部包依赖,适合作为你理解状态管理底层机制的起点。

function createStore(initialState) {
  let state = initialState;
  const entries = new Set();

  function getState() {
    return state;
  }

  function subscribe(selector, listener) {
    let prev = selector(state);
    const entry = { selector: selector, listener: listener, prev: prev };
    entries.add(entry);
    return function () {
      entries.delete(entry);
    };
  }

  function setState(partial) {
    const next = typeof partial === 'function' ? partial(state) : partial;
    state = Object.assign({}, state, next);
    entries.forEach(function (e) {
      const cur = e.selector(state);
      if (cur !== e.prev) {
        e.prev = cur;
        e.listener(cur, state);
      }
    });
  }

  return { getState, subscribe, setState };
}

// 使用示例
const store = createStore({ count: 0 });
const unsub = store.subscribe(
  function (s) { return s.count; },
  function (c) { console.log(c); }
);
store.setState({ count: 5 });
unsub();

JavaScriptstate_managementpublish_subscribe修改时间:2026-08-03 21:06:15

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。