为什么需要 KeyMirror

茧型元组
• 阅读 6145

前言

今天有朋友问了 “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);

最后输出的结果如下:

为什么需要 KeyMirror

然后就是相当于重新生成了一个 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

原文出自:http://60sky.com/post/why-key-mirror.html

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Morning Morning
4年前
前端容易理解错的跨域原理
前言关于跨域这件事,自从我遇到后,了解一下,这事就过去了。我也一直认为这是个小问题,大家应该都懂。直到我要教妹妹前端时遇上这个问题才发现,这个问题得整个逻辑讲出来其实还挺绕的。知道问题怎么解决很简单,但是要讲清楚问题为什么出现就十分复杂了。那么我突然就好奇了,大家是都懂这个逻辑了嘛。所以我在几个交流群里问了一个问题为什么很多人都出现本地环境会跨域而线上环境
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Karen110 Karen110
4年前
​一篇文章总结一下Python库中关于时间的常见操作
前言本次来总结一下关于Python时间的相关操作,有一个有趣的问题。如果你的业务用不到时间相关的操作,你的业务基本上会一直用不到。但是如果你的业务一旦用到了时间操作,你就会发现,淦,到处都是时间操作。。。所以思来想去,还是总结一下吧,本次会采用类型注解方式。time包importtime时间戳从1970年1月1日00:00:00标准时区诞生到现在
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
JOptionPane修改图标
1.在Linux平台下.JOptionPane会显示Java默认的图标,在window平台不显示图标,如何替换这个图标了?2JOptionPane.setIcon(Icon)修改的是内容区域的icon,而不是左上角的Icon.所以需要通过修改Jdialog/Frame的图标来达到修改默认图标的问题.3.代码:if(JOptio
Wesley13 Wesley13
3年前
NEO从源码分析看网络通信
_0x00前言_NEO被称为中国版的Ethereum,支持C和java开发,并且在社区的努力下已经把SDK拓展到了js,python等编程环境,所以进行NEO开发的话是没有太大语言障碍的。比特币在解决拜占庭错误这个问题时除了引入了区块链这个重要的概念之外,还引入了工作量证明(PoW)这个机智的解决方案,通过数学意义上的难题来保证每个
Python进阶者 Python进阶者
2年前
盘点一个Python导包的问题
大家好,我是皮皮。一、前言前几天在Python白银群【王者级混子】问了一个Python导包的问题,这里拿出来给大家分享下。有大佬知道为什么用.ipynb导入其他文件夹内它会说没有这个文件,但用.py导入却可以正常运行呢?他的代码截图如下:二、实现过程这里【
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这