w3ctech

为什么需要 KeyMirror

前言

今天有朋友问了 “KeyMirror” 这个库有什么用的问题,其实这个问题并不难,这里扫一下盲区。

会按照下面这个逻辑来展开,彻底理解一下:

  1. KeyMirror 有什么用?
  2. Google Closure Compiler 是什么?
  3. KeyMirror 解决了什么问题,好处是什么?
  4. KeyMirror 的源码是什么样子?
  5. 用 Gulp 配置一个压缩任务,测试一下 Google Closure Compiler.

一、KeyMirror 有什么用

直观的来看一下,测试代码如下:

var kv = {
    GET_USER: null,
    SET_USER: null,
    REMOVE_USER: null
};

// keyMirror 是对应的测试方法
var kv_new = keyMirror(kv);
console.log(kv);
console.log(kv_new);

最后输出的结果如下:

kv

然后就是相当于重新生成了一个 key == value 的结构。但是肯定就会想,为毛要多此一举呢?其实这个跟 Google Closure CompilerAdvanced 模式有关。接下来我们来看一下它是什么。

二、Google Closure Compiler 是什么

如果有兴趣的朋友可以直接跳到文章后面,使用 Gulp 把环境搭起来测试,因为下面的地址都要翻墙!

有官方文档,需要翻墙:文档

大致的意思就是说,Closure Compiler 是一个工具,这个工具能够编译 JavaScript 代码,编译后的代码能下载更快并且执行也更快。它能够解析你的 JS 代码,并且去分析它,能移除没有使用到的代码,重写、压缩得到最终的生产环境下的 JS 代码。它拥有检测语法、变量声明、类型定义以及对 JS 语言缺陷做一些检查。

总之,这就是做 JS 编译并且做一些常用检测的一款工具。

具体能够在线体验,也需要翻墙,在线体验地址

这个工具有三种模式:

  1. 只去空格( Whitespace only )
  2. 简单处理( Simple )
  3. 最优处理( Advanced )

用 KeyMirror 的原因就是因为第三种(Advanced,最优处理)模式下,会将 Map<K, V> 格式的 K 进行压缩,比如:

// 源代码
var kv = {
    GET_USER: null,
    SET_USER: null,
    REMOVE_USER: null
};

// 编译后( 整理了一下格式,实际情况下会再添加压缩 )
var a = {
    a: null,
    c: null,
    b: null
};

在引用的时候就变成:

// 源代码
var kv_new = keyMirror(kv);
console.log(kv_new.GET_USER);

// 编译后
var a = keyMirror({ a: null, c: null, b: null });
console.log(a.a);

这样如果在没有进行 KeyMirror 处理的时候,引用就会错误了,这种编译模式破坏了我们的代码,要避免这个编译导致的 Key 改变,可以给 Key 添加引号(单、双均可),其实能够分析的就是静态的属性,动态基本上是不好做好的,可以这样理解。

// 源代码
var kv = {
    'STOP_USER': null
};

// 编译后
var a = {
    STOP_USER: null
};

然而我们这样做了之后,代码就得不到更有效的压缩,这样 Closure Compiler 的功能就被削弱了,所以引入 KeyMirror 既能保证代码前后的功能一致,也能享受压缩带来的性能提升。

三、KeyMirror 的源码是什么样子

既然知道了上面的背景和原因,我们来看下如何实现一个这玩意,其实特别简单的功能,就是让 K,V 相等。

var keyMirror = function(obj) {
    var ret = {};
    var key;

    // 对参数的控制,必须是对象
    if (!(obj instanceof Object && !Array.isArray(obj))) {
        throw new Error('keyMirror(...): Argument must be an object.');
    }

    // 简单的遍历,将对应 K 赋值给 Map[K]
    for (key in obj) {
        // 只拷贝自己的属性
        if (!obj.hasOwnProperty(key)) {
            continue;
        }
        ret[key] = key;
    }

    return ret;
};

四、Gulp 配置测试 Closure Compiler

这里需要用到两个东西:gulp、google-closure-compiler-js

直接上代码:

var gulp = require('gulp');
var compiler = require('google-closure-compiler-js').gulp();

gulp.task('go', function () {
    return gulp.src('./index.js')
        .pipe(compiler({
            // 编译等级,不区分大小写哈
            compilation_level: 'advanced',
            warning_level: 'VERBOSE',
            output_wrapper: '(function(){\n%output%\n}).call(this)',
            js_output_file: 'index.advanced.min.js',
            create_source_map: true
        }))
        .pipe(gulp.dest('.'));
});
// 测试代码
var kv = {
    GET_USER: null,
    SET_USER: null,
    REMOVE_USER: null
};
// 必须要和 keyMirror 代码一起,不然会被提示 error。
// Error: Compilation error, 1 errors
var kv_new = keyMirror(kv);
console.log(kv);
console.log(kv_new);

亲测非常的慢,不知道是不是我姿势不对,advanced 模式都是花费 12s 左右,simple 模式也花费 8s 左右,第一次测试我还卡挂了,所以基本上代码量上去了感觉是不适用的。

参考地址:

[1] https://developers.google.com/closure/compiler/

[2] https://github.com/facebook/react/issues/1639

[3] https://gist.github.com/zpao/d25251b139647a79cddf

[4] https://www.npmjs.com/package/keymirror

w3ctech微信

扫码关注w3ctech微信公众号

共收到0条回复