Injector框架理解(一)

在可测试js的框架学习过程中,我们不断提到了依赖注入,依赖注入使用最多的就是在java中的spring,为了在js中使用依赖注入,我们今天学习另一个不那么常用的框架:didi

首先看看安装命令

npm install didi

这个时候,我看到项目下的package.json

{
  "name": "babelwebpack",
  "version": "1.0.0",
  "description": "babel webpack ingegraty",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "pack": "webpack",
    "publish": "webpack-dev-server --output-public-path=/dev/"
  },
  "keywords": [
    "babel",
    "webpack"
  ],
  "author": "hk",
  "license": "ISC",
  "devDependencies": {
    "@babel/cli": "^7.18.10",
    "@babel/core": "^7.18.13",
    "@babel/preset-env": "^7.18.10",
    "webpack": "^5.74.0",
    "webpack-cli": "^4.10.0",
    "webpack-dev-server": "^4.10.1"
  },
  "dependencies": {
    "babel-loader": "^8.2.5",
    "didi": "^9.0.0"
  }
}

我再贴出我的webpack.config.js

var path = require('path');

module.exports = {
   entry: {
      /** 源代码根路径 */
      app: './src/main.js'
   },
   output: {
      /** 这里配置的是webpack的打包输出路径 */
      path: path.resolve(__dirname, 'dev'),
      filename: 'main_bundle.js'
   },
   mode:'development',
   module: {
      rules: [
         {
            test: /\.js$/,
            include: path.resolve(__dirname, 'src'),
            loader: 'babel-loader',
            options: {
               presets: ['@babel/preset-env']
            }
         }
      ]
   },
   devServer: {
      static: {
         /**这里配置的开发服务器的根路径 */
         directory: path.join(__dirname, './public'),
      },
      hot: true,
      compress: true,
      port: 9999,
   },
};

好了,我要开始使用didi

首先我定义三个组件:

const {Injector} =require('didi');
function Car(engine) {
    this.start = function() {
      engine.start();
    };
}
  
function createPetrolEngine(power) {
    return {
      start: function() {
        console.log('Starting engine with ' + power + 'hp');
      }
    };
}
  
// define a (didi) module
// it declares available components by name and specifies how these are provided
const carModule = {
    // asked for 'car', the injector will call new Car(...) to produce it
    'car': ['type', Car],
    // asked for 'engine', the injector will call createPetrolEngine(...) to produce it
    'engine': ['factory', createPetrolEngine],
    // asked for 'power', the injector will give it number 1184
    'power': ['value', 1184] // probably Bugatti Veyron
};
  
// instantiate an injector with a set of (didi) modules
const injector = new Injector([
    carModule
]);
  
// use the injector API to retrieve components
injector.get('car').start();
  
// ...or invoke a function, injecting the arguments
injector.invoke(function(car) {
    console.log('started', car);
    car.start();
});

大家注意以上代码,我们需要指出几个概念,首先理解什么是组件,什么是模块,什么是依赖注入加载器

组件可以是一个类,一个函数,甚至是一个值,在以上的代码中,有一个叫做Car的组件,一个叫做Engine的组件,以及一个叫做power的组件,而这三个组件又构成了一个模块,叫做carModule,这个模块通过依赖注入加载器加载以后,我就可以使用这些组件啦。

使用组件的方式有两种,第一种通过调用get()方法拿到组件以后,再使用。

另一种是通过调用invoke方法,通过一个函数来获取依赖注入参数,然后再使用。大家可以运行代码试试效果,不过呢,这里有个小问题就是,只有在编辑状态的时候才能运行代码,而且只支持node的require引入,不知道这个部分以后是否可以优化。

 

我们再举一个例子

const {Injector} =require('didi');
class BubType{
    constructor() {
      this.name = 'bub-value';
    }
}

function BuzType() {
    this.name = 'buz-value';
}

/**
  * 在一个模块定义了四个组件
  */
const newInjector = new Injector([
    {
      foo: [
        'factory',
        function() {
          return 'foo-value';
        }
      ],
      bar: ['value', 'bar-value'],
      bub: ['type', BubType],
      buz: ['type', BuzType]
    }
]);

console.log('foo:',newInjector.get('foo'));
console.log('bar:',newInjector.get('bar'));
console.log('bub:',newInjector.get('bub'));
console.log('buz:',newInjector.get('buz'));

这里我们大概理解了基本的用法了吧,其实这个简单的框架为我们组织前端的代码提供了很好的组织方式,能够让我们的代码更加模块化。欢迎大家一起讨论学习。

版权声明:著作权归作者所有。

相关推荐

[译]iOS开发可复用框架入门(实例)

当你编写一个iOS应用程序时,你通常会什么都不想就导入Foundation或UIKit框架。 如果要使用字符串,日期,文件系统或线程,可以导入Foundation。如果要使用UITableViewController或UIAlertController,则可以导入UIKit。 如果你导入了UIKit,那么可以完全忽略Foundation,因为UIKit在后台会导入它。关键是这些

Go语言日志框架logrus封装

logrus在github上是一个star数比较高的go日志框架,简单封装如下:package log import ( "fmt" "github.com/Sirupsen/logrus" "runtime" "strings" ) var logger = logrus.New() // 封装logrus.Fields type Fields logrus.Fields func SetLog

Go日志框架logrus的基本用法

以package级别方式使用logruspackage main import ( "os" log "github.com/sirupsen/logrus" ) func init() { // 设置日志格式 log.SetFormatter(&log.JSONFormatter{}) // 设置输出 log.SetOutput(os.Stdout) // 设

JPA架构(JPA - Architecture)

今天我们来学习一下JPA的架构,首先问一个问题,大家学习理解一个架构有什么好的方法呢?对于我自己来说,我觉得架构图是理解架构最好的方式以上就是JPA的架构图,我们可以知道,JPA的主要部分包括五个类: 第一个类EntityManagerFactory,我们可以称为实体管理器工厂类,很显然,这个类的作用是创建和管理多个实体管理器类,因此,我们可以大胆猜测,实体管理器工厂类和实体管理器是一对

RxJs——subject理解一

什么是subject首先我们来理解什么是subject,按照官方的定义:A Subject is a special type of Observable that allows values to be multicasted to many Observers.Subjects are like EventEmitters.从定义我们看出subject就是一种允许发送值到多个观察者的特殊类型的

RxJs——Subject理解二

上一节我们对subject有了初步理解,今天我们继续学习subjectReplaySubject介绍这个ReplaySubject之前,我们说下一种使用场景1、我们创建一个subject2、在应用的某个地方,我们向subject推送值,但此时没有订阅3、在某个时点,有第一个观察者开始订阅4、我们期望观察者能接收之前主题推送的值(可能是全部值或者时其中一个)5、实际上啥都没发生,因为主题不能存储记忆

CKEditor5——模型理解(一)

我们知道,CK5实现了一个MVC的架构,从今天开始,我们一步一步深入学习模型,视图,以及模型和视图之间的转换。今天我们开始模型的学习。首先,我们看模型的定义:The model is implemented by a DOM-like tree structure of elements and text nodes.模型由两类节点构成,分别是元素节点和文本节点,模型是一种类Dom树结构。我们知道

CKEditor5——模型理解(六:Range)

上一节我们主要介绍了模型中的Position这个关键的类,今天我们开始学习Range这个类。简单来说的话,如果Position表示一个点的话,那么Range是不是可以理解为一条线段呢?这个线段有一个startPostion,endPosition以及线段的长度等属性,我们暂且这么认为,那么我们可以看看Range官方的文档。从文档中看到,Range类有五个属性:Range属性start:Positi

CKEditor5——模型理解(七:Selection)

昨天我们学习了Range的一些API使用,今天我们看看另一个重要的类Selection的API:Selection的作用是记录鼠标在文档上的选择区域,如果是单个用户在编辑一份文档的时候,选择应该就是一个Range,如果是多个用户在编辑一份文档的时候,那么选择的区域就应该是多个range。因此,我大胆的猜测,Selection中应该有Range数组。我们来看看吧。Selection属性anchor

RxJs——Subscription理解

我們前段時間學習了Observable相關的知識,今天我們學習另一個重要的概念:Subscription。首先,我們看看Subscription官方文檔的介紹如下:What is a Subscription? A Subscription is an object that represents a disposable resource, usually the execution of an