V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
yfsoftcom
V2EX  ›  分享创造

nodejs 如何实现一个简单的插件扩展

  •  
  •   yfsoftcom · 2017-02-21 21:10:31 +08:00 · 5111 次点击
    这是一个创建于 2619 天前的主题,其中的信息可能已经有所发展或是发生改变。

    为什么需要插件扩展?

    • 模块化思想

    任何一个易用的系统都强调易用,易维护,模块化是 nodejs 的核心思想(显然并不是 nodejs 首先提出的); nodejs 有很多优秀的 package 都支持插件式开发: hexo(非常流行的静态博客生成工具),egg(ali 团队推出的企业级开发框架),etc...


    当然模块化不仅仅限于使用插件化的方式;还有 node web 开发中非常常见的中间件模式。


    总之,无论是 oop 、中间件、插件化这些设计模式都是为了更加解耦、更加抽象、更加易读、易用、易维护。

    • 扩展更加便捷

    好的设计模式可以做到不需要对现有的系统代码做任何修改,对现有代码无侵入的情况下做到功能拓展。插件机制就是一种很常见的设计模式,可以用最小的成本满足大部分的应用场景。

    • 核心代码更纯粹

    插件可以随时添加,任意添加,对已封装的核心代码没有任何改变,核心代码更加纯粹,保持最精简的状态,极大程度的避免了快速迭代过程中造成核心崩溃的情况。

    如何实现插件扩展机制?

    • 反射机制

    java ,.net 等 oop 语言都有反射机制,即可以根据类名动态加载类的信息到内存或虚拟机中,完成对象的创建。这种反射机制是现在流行的主流框架的基本实现手段,它们之所以如此优秀于灵活,就是因为这种机制提供了更自由的扩展于变化;让 coder 更关注业务。

    • require

    nodejs 并没有反射机制,因为它本身是非编译型的,为了能有更好的扩展, nodejs 设计了 require 机制,可以通过 require 函数自由的加载需要的模块,某种意义上说:

    require 就是 nodejs 的反射机制!

    但是 nodejs 在不断更新,慢慢会出现更好的特性,必然也会实现其反射机制。不过就目前来看, require 已经可以满足我们实现插件化开发了。

    • hook

    hook 即钩子,是一种在 php 系统中使用较为多见的概念,比如非常著名的博客系统: wordpress ,就有非常多丰富的插件;而插件的基础就是 hook !假设一个模型:

    // code list 1:
    var core = { 
     run: function(){
       console.log('hi there~');
     }
    };
    
    core.run();
    // hi there~
    

    针对这样的设计,我们无法完成任何事情,想要在 run 之后执行一些其它的操作,只能修改它的代码比如:

    // code list 2:
    var core = { 
     run: function(){
       console.log('hi there~');
       console.log('an other greeting~');
     }
    };
    
    core.run();
    // hi there~
    // an other greeting~
    

    这样的设计无法满足动态的需求,本身的核心代码也无法进行封装,因为随时需要修改它。


    下面进入正文:

    // code list 3:
    var core = {};	//初始化
    core.hooks = {};	//定义钩子集合
    
    /*添加钩子的函数,这里是重点*/
    /*钩子名,钩子函数*/
    /*将一个函数添加到 core 对象的钩子集合中*/
    core.addHook = function(hookName, hookFunction){
      var hookList = core.hooks[hookName];
      if(hookList){
        hookList.push(hookFunction);
      }else{
        hookList = [ hookFunction ];
      }
      core.hooks[hookName] = hookList;
    };
    
    /*执行钩子集合中的钩子函数*/
    core.runHook = function(hookName){
      var hookList = core.hooks[hookName];
      if(hookList){
        for(var i = 0 ; i < hookList.length ; i++){
          hookList[i]();
        }
      }
    };
    
    /*核心入口函数*/
    core.run = function(){
      core.runHook('before_run');
      console.log('hi there~');
      core.runHook('after_run');
    };
    
    core.run();
    // hi there~
    
    /*当然此时,写了这么多代码,也只是和 code list 1 实现的功能一样*/
    

    重点来了:

    如果我们想实现 code list 2 的功能,我们似乎根本不需要修改 core.run 的代码:

    // code list 4:
    
    code.addHook('after_run', function(){
      console.log('an other greeting~');
    });
    
    code.run();
    // hi there~
    // an other greeting~
    

    简单的添加一个 hook 函数就可以实现 code list 2 实现的功能了,当然我们还能在这个基础上实现更多。 而这个就是一个简单的插件化开发模型;在此基础上不断的提高核心代码的健壮和容错性就可以将核心代码进行封装发布,提供丰富的钩子和 api 供插件开发者实现更多优秀的扩展。

    总结

    一个 nodejs 模块尽量精简,保持较小的体积,可以让它更轻便,优雅,插件化开发可以让你的 package 被更多人使用和喜欢。

    bdbai
        1
    bdbai  
       2017-02-21 22:43:05 +08:00 via Android
    Nodejs 事件机制不是一个现成的钩子实现?
    yfsoftcom
        2
    yfsoftcom  
    OP
       2017-02-22 00:15:22 +08:00 via iPhone
    @bdbai 事件是异步回调 与钩子不是一回事
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5425 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 09:11 · PVG 17:11 · LAX 02:11 · JFK 05:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.