抄了一个框架玩玩。。。

2017-12-01 17:12:24 +08:00
 supermao

now.js 是什么

now.js是一个 javascript 的时间操作小工具,类似date-fnsmoment

长啥样

简单的把示例放这,更多用法请到github去发现。

import Now from 'now.js'; // for node(browser do not need this)

now = new Now() // "2017-11-20 22:23:00.285"

now.beginningOfMinute()   // "2017-11-20 22:23:00"
now.beginningOfHour()     // "2017-11-20 22:00:00"
now.beginningOfDay()      // "2017-11-20 00:00:00"
now.beginningOfWeek()     // "2017-11-19 00:00:00"
now.firstDayMonday = true // Set Monday as first day, default is Sunday
now.beginningOfWeek()     // "2017-11-20 00:00:00"
now.beginningOfMonth()    // "2017-11-01 00:00:00"
now.beginningOfQuarter()  // "2017-10-01 00:00:00"
now.beginningOfYear()     // "2017-01-01 00:00:00"

now.endOfMinute()         // "2017-11-20 22:23:59.999"
now.endOfHour()           // "2017-11-20 22:59:59.999"
now.endOfDay()            // "2017-11-20 23:59:59.999"
now.endOfWeek()           // "2017-11-25 23:59:59.999"
now.firstDayMonday = true // Set Monday as first day, default is Sunday
now.endOfWeek()           // "2017-11-26 23:59:59.999"
now.endOfMonth()          // "2017-11-30 23:59:59.999"
now.endOfQuarter()        // "2017-12-31 23:59:59.999"
now.endOfYear()           // "2017-12-31 23:59:59.999"

All the above functions return String type. You can pass 'self' to return Now instance:

var beginningOfMinute = now.beginningOfMinute('self') // return Now instance
beginningOfMinute.format('ddd, Ah') // "Mon, PM10"
beginningOfMinute.format('LLLL') // "Monday, November 20, 2017 10:23 PM"
beginningOfMinute.isMonday() // true

为什么要写这个库

因为学习underscore源码的过程中,感觉无聊。想写个库调剂一下,当做学习的机会。
我是照着underscore源码一个个 commit 敲的.代码放在这里,刚看了一眼,有 668 次 commit,两个月,敲到了 1.4.3 版本,可能还没到一半。
敲久了有点无聊。想动手写一个库作为调剂。碰巧之前做防健忘短信提醒的时候是用 go 写的后台,用了gorm,在作者jinzhu的 github 主页上发现了now,是一个 go 的时间帮助库,觉得很有意思。clone 之,学之。
偷了now的思想。造一个 javascript 版的就显得很容易。很快我就写完了除了ParseMustParse之外的所有方法。跟原库对比一下。觉得 now.js 就是个玩具。这不怪我,javascript 对时间处理的支持远不如 go。比如 go 原生支持format、字符串解析成时间以及Duration等等。
想着加上format。该怎么去写?立马就想到的方法是平时经常写的根据不同条件做字符串拼接。确实是个方法。但得多少 switch case 才能涵盖所有情况,想想都可怕。显然这是最蠢也是工作量最大的方法。
不会,那就借鉴别人的。github 上发现了 date-fns 和 moment,支持 i18n 国际化。

date-fns:

import { formatRelative } from 'date-fns'
import { es, ru } from 'date-fns/esm/locale'

formatRelative(subDays(new Date(), 3), new Date(), { locale: es })
//=> "el viernes pasado a las 19:26"

formatRelative(subDays(new Date(), 3), new Date(), { locale: ru })
//=> "в прошлую пятницу в 19:26"

moment:

moment.locale('fr');
moment(1316116057189).fromNow(); // il y a une heure
moment.locale('en');
moment(1316116057189).fromNow(); // an hour ago

我的审美告诉我应该选择 moment,调用一次 locale(),这之后的 format 都是基于该 locale 的。当然它也还支持每次单独指定 locale 的:

moment.duration(1, "minutes").locale("en").humanize(); // a minute
moment.duration(1, "minutes").locale("fr").humanize(); // une minute
moment.duration(1, "minutes").locale("es").humanize(); // un minuto

进一步学习发现 moment 的 format 和 i18n 国际化高度耦合。要用它的 i18n 意味着基本上也得用它的 format。当然 i18n 也不是核心的 moment 库作者写的,他们也精通不了那么多国家的语言,那都是 github 上许许多多人贡献的。开源就有这好处。看下 LICENCE 是 MIT 的,代码可用,抄。
now.js 也是 MIT 协议的,负罪感少了点(其实 MIT 协议是相当宽松的,就算你拿它代码去商业化也是没有问题的)。况且我写库的主要目的是为了学习。
开干!虽说是抄,毕竟代码要整合到我的库,直接复制粘贴是不行的。所有的代码细节未必都需要全知道,但看懂整体运行的逻辑是必须的,下点功夫,整合成功,开源。

思维脑图

moment:

当然,moment 的东西不止上图这些,我只取了一部分来画。

now.js:

now.js 的 Duration 和 moment 的不一样,现在还不支持单独使用,只是给内部方法elapse使用,以后可能会支持单独使用。

对比

  1. moment 是大而全,now.js 是刚够用。
  2. moment 的 parse 相当强大,now.js 就暂时不支持了,只支持和new Date(args)相同的args参数类型。不过format应该都基本上和 moment 的一样,不过测试用例现在还没有写太全,如果谁用了并且发现 bug,可以到github去提 issues。不胜感激。
  3. moment 是页面一加载的时候会把所有的 i18n 都初始化了,这点我个人认为不好,加载时间长,网络情况不好的时候,差不多需要 10 秒我才能在 devtool 上调试(当然这也包括官网加载的其他很多东西)。now.js 只加载默认的,需要的时候按需加载。
  4. moment 做什么操作前都要检测一下 date 是否合法的( isvalid )。now.js 在 parse 的时候如果不合法就直接抛出错误,以免后续没玩没了的检测。当然这可能损失了用户友好性,但是对减少代码量是很有帮助的。

结语

这个库不是我一个人写的,是许多开源工作者共同完成的。感谢 moment 的所有开源贡献者,我从中学习了很多东西。后续还会继续研究 moment 的代码细节,偷偷它的思想。

写代码什么最重要?思想最重要!

2229 次点击
所在节点    前端开发
7 条回复
Pastsong
2017-12-01 17:25:20 +08:00
设全局状态这件事情太不 functional 了...
supermao
2017-12-01 17:32:10 +08:00
@Pastsong 没错,现在这个只是第二个小版本,主要还是学习学习,慢慢再想怎么提高
wyc829
2017-12-04 15:52:20 +08:00
支持
supermao
2017-12-05 13:17:18 +08:00
@wyc829 多谢!
brooky
2017-12-20 14:44:09 +08:00
小白一个, 才知道原来是这样学习别人代码的. 但是看了下没有注释啊, 看不懂啊
underscore 有 2000 多 commits 怎么迅速找到第一个 commit, 而不是一个个点击`older`
supermao
2017-12-20 22:08:37 +08:00
@brooky 其实我觉得我的命名已经能够很好的理解意思了,所以没加注释,等 1.0.0 再加吧
supermao
2017-12-20 22:10:13 +08:00
@brooky clone 库 然后 git log 就行 当然可以配合 shell 脚本的 tail 等来看 自己发挥了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/411194

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX