既然来了

最近的事情有点多,再加上自己想的也多,所以有很多烦恼。
包括待人接物,处理事情,项目管理等一堆烦恼堆积在身边,不知道用什么态度去处理比较好。

晚上一边啃泡面,一边看着Bilibili的中国诗词大会比赛视频。
直接看了决赛获奖者武亦姝的那一场,觉得很喜欢她这种在比赛中的表现与对诗歌的热爱,于是又去看了她之前的比赛。

【中国诗词大会】武亦姝 cut合集的第一个视频中,看到了她的自我介绍与准备。最后在总结时她说了一句:

我是武亦姝,既然来了就做到最好吧。

说话的时候悠然且闲适,仿佛习惯了如此这般。

在电脑面前啃泡面的我,一瞬间触动万千,也想通了很多事情。

编程源于热爱,偶尔也会有不知道如何选择,该去哪儿,该做什么,做到什么样的时候。
现在的话,倒是突然有了自己的态度和想法。

我是刘子健,既然来了就做到最好吧。


如果你觉得我的文章对你有帮助,请支持我。让我写出更好的文章。

支付宝付款 微信付款

生活

如果天空是黑暗的,那就摸黑生存;如果发出声音是危险的,那就保持沉默;如果自觉无力发光的,那就蜷伏于墙角。但不要习惯了黑暗就为黑暗辩护;不要为自己的苟且而得意;不要嘲讽那些比自己更勇敢热情的人们。我们可以卑微如尘土,不可扭曲如蛆虫。


如果你觉得我的文章对你有帮助,请支持我。让我写出更好的文章。

支付宝付款 微信付款

2017-当行远方

又是一年圣诞夜

去年的这个时候,自己全心全意的投入于编程这项活动中。面对着或多或少的质疑,提笔写下了一篇短文《拥抱自己所热爱的,即是正义。》
拥抱自己所热爱的,即是正义。

无关风月,没有胜负。只是心有猛虎,即使只是做困兽之斗,也不甘被任何人束缚。

2016这一年

在前些天写的文章《2016-编程元年》中,有简单的提到这一年做的事情,但是没有细说。现在正好回顾一下。

前端-从一到N

首先要提的还是前端方面。如果说去年的第一次Ajax,让我正式跨入了前端的大门,那么今年所做的一切,都在不断拓宽我对前端的认识, 开始向一名JavaScript Full Stack程序员蜕变。

当然现在很多人是不认同JavaScript Full Stack的。但我觉得,无论用什么语言,能让我以较低的成本,适合的方式去完成一个产品都是值得的。然后JavaScript的出现正好满足了我的需求。

JavaScript

首先要说的,应该就是JavaScript的学习。这一年来积极关注社区动向,努力学习JavaScript的最新规范。从一年前的磕磕绊绊,ES5都很难写好和理解透彻,到现在熟练使用ES6/7去完成任务。同时对JavaScript语言理解的加深,也能利用其“特性”去实现一些小tricks。

包括说前些天写的,利用Decorator去写Koa的路由。中间的Hack意味就非常浓。具体有时间,写篇博客记录其实现方式~

TypeScript-不止JavaScript

另一个突破在于TypeScript,一门转译到JavaScript的语言。
起因是我在用习惯ES6的时候,就在一直思考,有没有一种更好的方式,让我更高效的编写代码,从而提升开发体验与效率。
于是在十一月的某一天,又一次盯上了TypeScript。
是的,又一次……
说来,很惭愧……自己其实在今年四五月份就盯上了TypeScript,可是当时不知道怎么配置环境,也因为各种Typings文件的安装而烦恼……所以一直没有成功。
所幸在TypeScript发布2.0后,情况大有改观,Types文件安装起来简单顺手,自己也开始习惯使用VSCode与默认配色(默默吐槽一句,默认配色真的好不习惯啊……看到的时候简直没有写代码的动力)

TypeScript 2.0发布后,开始学写TypeScript,遇到问题也是积极去解决,而不是躲回原生JS的背后,继续写着和之前一样的代码。同时也在积极寻找项目,甚至创造项目,去用TypeScript写或者重构。

时至今日,用TypeScript还会有磕磕碰碰的感觉,但是比之前顺溜多了,也能完成相应的项目。而Types文件所带的详实准确的代码提示,确确实实的提高了开发效率。类型系统的存在,能极大的减少自己因为类型不清,而出现一些低级问题。

总的来说,感觉还是很棒的。

Koa2-Easy - 不止浏览器端

因为去年对Express的学习和使用,知道了自己对于后台框架的真实需求。
同时苦于每次使用Koa时,装插件的繁琐,于是从零开始,组装了一个适合自己的Koa框架。
自己写了项目的骨架/cli 以及配套的中间件,部署等工具。
经过一次又一次的调试,对中间件的挑挑拣拣,最终搭配成了最符合自己需求的一套工具。
然后放在Github开源了。项目刚开始的时候,还写了一篇《从零组装新工具 - Koa2》

截止到今天,自己提交了148次代码,获得了60个Star。这个也算自己始料未及的事情。
甚至说还有用户,真正的在使用我的框架,认真的去提issue。
感觉,能帮助到他们,自己的产品有人用……真的是好棒啊。

React Native - 不止Web端

在写Web相关应用的时候……看到了Weex的开源,在开发者大会上也听到了CrossWalk这种优秀的跨平台开发工具,还盯到了React Native的蓬勃发展……
自己的心……开始躁动不安了……
开始在思考自己怎么样去做一个App。
今年八月开始,自己接触了Cordove等Hybird App与Weex的解决方案后,觉得都差强人意。堪堪够用但是又感觉缺了点什么,性能和可拓展性都是阻碍自己的原因。
于是决定尝试一下React Native。
七天后,我的第一个App就上线了。

在剩下的日子了,仿佛上了瘾一般,开始疯狂的迭代App。把所有能用JavaScript写的,都写一遍。把不能用JavaScript写的部分,去网上找教程,加入iOS和Android的原生模块。

当然,版本号也从一开始的1.0.0……两三个月内狂飙到5.0.1……
中间也知道了写一个App,与写一个Web项目的不同。提交App给AppStore,却因为截图问题,被打回来好几次。想更新App但是无奈iOS审核太慢,于是尝试了热更新方案。
诸如此类的事情还有很多很多……个中滋味只有自己能够体会。

设计/交互/产品 - 不止前端

曾经有人在一年前问我:“你觉得什么是前端?”
当时我给的回答是:“前端是一个程序员+半个后台+半个产品经理+半个UI设计。前端之所以为前端,就是因为不局限与浏览器的简单前端。而是关注人机交互的‘大前端’。”
现在看来,自己这一年所做的事情,和当时的回答,基本一致。
自己在学习前端相关,计算机相关内容之外,还会去主动学习设计/交互/产品等方面的书籍。并且对我自己的成长起了较大帮助。至少,和一起做项目的小伙伴交流时,不会是抓瞎的状态了。能和他们顺畅的交流需求,知道怎么做前后盾配合更好,知道怎么做,UI和前端的对接更快。这些都是属于自己在学习过程中,得到的宝贵收获。

Docker - 与技术潮流接轨

另一个不得不提的事情,是自己学会使用Docker。嗯,虽然只是简单的使用,但已经确实体验到了Docker在运维上的便利。不用担心每到一台主机上,都得重装环境,也不用担心应用冲突等烦心的问题。
简单的拉取镜像,并且用Docker-Compose一键部署,便可完成复杂的部署工作。
不得不说,会用一些Docker,对于个人效率的提升还是很有帮助的。

开发者大会

七月份,参加了北京的Node Party, 九月份,参加了JSConf。
至于要说收获的话,见仁见智吧……
Node Party上,看到了同为人力资源管理文科生的同学,现在用Node.js用的很6。
也在JSConf,得以见到诸多大牛,与贺师俊前辈的一番交流,更是受用至现在。
到现在还记着贺师俊前辈在我道谢之后,说的那一句话:

“没有什么的,如果我的交流能给你们这些年轻的工程师带来些许帮助,就再好不过了。”

当时瞬间荣誉感爆表……感觉自己在大牛的祝福下,完成了从学生到年轻工程师的蜕变。

算法

嗯……还是不得不提这个。算法与数据结构是心头大患,因为自己数学并不是很好,所以学起算法来会感觉到吃力……
不过还好,自己没有放弃。现在对于算法的掌握程度,可以算是入门啦~坚持多学一点点,虽然工作中基本用不到,但是掌握知识本身,就是一件很开心的事情。

家园 - 从零到一

掐指一算,自己加入家园工作室,也将近有两年时间了。
如果说大学期间自己做的最正确的一件事,那么一定是加入家园。

从接触前端,再到正式入门,直至现在的全面开花,无一不与家园相关。
而自己也从去年的索取者,转向为家园做点什么的贡献者。

在工作室的分享会

16年在工作室这儿,陆续开了三场分享会。
分别是《前端的新方向》,《REM + Flex 布局 》和《你好,校招》。

两个与职业相关,一个则是与自己专业相关。至于效果,只能说自我感觉良好……

开发部の分享会制度

开发部之前,是没有成型的分享会的。有的也只是说个人的小型分享会。
在意识到这个问题之后,觉得应该做一些改进。
于是在开发部这儿,推行了分享会制度。
至于效果,应该算是出其意料的好。每周想分享的人都要排队。

工作室转型 - 阵痛

很快到了学期末,工作室面临着换届的问题。自己努力争取,进入了工作室的中心组(可以理解为决策层)。

因为自己在工作室呆的这段时间,能察觉出不少问题。所以希望自己努力,能去改变点什么。
躲避固然轻松,祈祷纵然心虔,但工作室不会有任何改变。于是带着一车使命感,开始着手去做一些事情。

具体转型的问题,和几个同学+学长来来回回的讨论了两个月。中间的情况也是错综复杂。现在依然在进行转型,转型的怎么样,怎么转,希望明年的总结能给个答案。

有的时候,感觉家园像是一艘艨艟巨舰,而我就是那船长Coco,劈风斩浪指引方向。有时候却又觉得自己只是船上一名普通无比的水手,安心的做好自己的事情就行。最极端的时候,有觉得自己只是船底下的一条鱼,大船将倾,自己却妄图撑起来,结果也只能是被碾的粉碎。

项目管理 - 家园之殇

家园作为一只以产品为主导的团队,那么对于项目的管理自然至关重要。
然而长期以来,大家都使用/习惯使用 QQ 等方式进行交流。
而之前的学长学姐,也进行过类似的尝试,只是都因为各种各样的原因,废弃了。
到了我接棒的时候,依然遇到了类似的问题。项目管理混乱,很少有人知道其他人在做什么,大部分的时间浪费在无效的沟通上。
于是自然而然的产生了和学长学姐类似的想法,引入项目管理工具。
只是这次,是在充分调研和实践的基础上进行的。自己先是在各类项目管理工具的使用和调研基础上,选定了Teambition,并在部分小部分项目中使用。
后期也联系上了在Teambition工作的学长(人超级nice呀~)。最后因为收费等问题,切换到了Tower。

按照网站的历史,是会举办寒假比赛的。恰巧在引入Tower的时候,寒假比赛刚刚开始。于是将Tower算作考核项,开始推广给他们使用。也算是意外之喜吧,大一的学弟学妹对Tower不排斥,而且上手速度也很快。

这个事情依然在进展,希望井然有序的项目管理能对工作室有所帮助。

产品成长

家园作为一只以产品为主导的团队,产品的地位是很特殊的。
然而由于产品经理其职位的特殊性,基本属于可遇不可求的状态。
所以一直在思考,该怎么做,才能培养出产品经理,带领家园的产品向前走。

最后确定的方式是,给最大的硬件资源支持,给最大的人力物力支持,让他去折腾。
于是工作室这儿,一咬牙掏出了老底……出资购买了产品经理微专业。
希冀对网站的产品经理成长,有所帮助。

人才培养与更合理的招聘制度

身处南昌,互联网环境堪称贫瘠。
这是我在探索家园如何更有效的培养互联网人才,最深的体会。
整个的大环境不好,招人就难招。然而孤掌难鸣,只靠我们几个大三的,也很难保证走了之后,还能撑的下去。
于是在苦苦的思考过后,决定采用内部培养+外部招聘的方式进行。
内部好好培养,对外则改变一年只招新一次的方式,开始多次招新。
在招新的形式上,也改变之前一二三面就决定的情况。开始向互联网公司的招新形式靠近,同时结合学生的特点,开始做一些新的尝试。

具体的方式,看明年的培养效果。如果好的话写篇博客补上。

家园的核心

家园真正的核心是什么。
毫无疑问,是人。
无须赘述。
所做的一切一切,尽以人为本。只是时间和精力有限,做不到尽善尽美。

自我评价

这一年来,所作所为或许有可取之处,或许也有错误的地方。
有些东西,可能要好几年后才能看到结果。
总而言之,对于自己的评价:

已尽力而为,问心无愧。

生活与工作

这一年下来,生活方面,没有什么太大波澜却也没有什么太大的惊喜。除了感情方面,别的方面都挺顺利的。

身体方面的话,能明显感觉到是不如去年的。因为种种原因+自己懒,所以并没有去健身房健身也没有下去跑两圈。

工作

从今年三月份开始,就尝试着找大二的实习。
很幸运的接到了两份Offer,权衡再三后选择去了北京。

很高兴能遇到小兰姐这么棒的Leader,两个月的时间内基本全部在写JavaScript,这也使得我对JavaScript的理解进一步加深。
中途出去封闭开发了两周,遇到了非常棒的前端总监威哥。每天就是跟在威哥后面,听威哥去做分享,给我做CodeReview,看着各式各样炫目且实用的技巧。感觉对自己的成长帮助很大。那两个礼拜,也是过得“最无忧无虑”的两周。每天出门就是写代码,也不用挤地铁啥的。

做自己想做的,成为自己想成为的。

生活

生活的话,在北京也碰到了超级Nice的朋友/合租室友,还有超级暖的房东大哥大姐们。
感觉如果需要写下来,能写满满当当好几页~

2016,一生想做浪漫极客

在去年写的文章《2016,一生想做浪漫极客》中。黄玄学长送了一句寄语给我。

@Lxxyx 是一名大二的文科生,在本文中讲述了他因为兴趣走上程序员之路的故事。摘一段乔布斯的话作为寄语吧:「Your work is going to fill a large part of your life, and the only way to be truly satisfied is to do what you believe is great work. And the only way to do great work is to love what you do. If you haven’t found it yet, keep looking. Don’t settle. As with all matters of the heart, you’ll know when you find it. 」

很喜欢这句话,希望有缘看到这篇博客的你,也能找到自己所喜爱的事业。

2017-当行远方

17年到了。自己在今年也得正式的去面对春招,校招,找工作,是否考研等一系列事情。
这一切一切的事情,自己都不确定。
唯一能够确定的是,17年,自己会远离家乡,远离昌大,去往遥远且不确定的远方。
在大学的温室呆了太久,每日的生活就是寝室->机房->食堂的往复。
生活过于安逸的结果就是,容易自视甚高和自己感动自己。

去年在知乎上看到一段文字:

这些年我一直提醒自己一件事情,千万不要自己感动自己。
大部分人看似的努力,不过是愚蠢导致的。
什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。
人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。
——于宙《我们这一代人的困惑》

于是每当自己沉迷于安逸的现状或者开始自己感动自己时,便不断的去警醒,去催促,去推动自己走出去,去见识更广阔的天地。
去看看外面都市的繁华,去看看远方的山川河流,去见识各路大神,然后再被惨虐一番。

成就感

成就感是个好东西。但是一直沉迷于成就感,容易毁了自己。
这一点在16年中体会极其深刻。当做到很多别人暂时做不到的事情,自己的内心会像气球一样膨胀起飞。
这时候,只有靠着自己所剩无多的理智,自己亲手去把气球戳破。

就那种,“Pa!”的一声,整个人摔在地上,摔成一张饼那种。

每每戳破气球的时候,自己就会开始庆幸,又跨过了一个坎。
如果真的一直沉迷过去,沉迷那种虚假的成就感。迟早💊。

生活的正轨

自己在某些时候,会觉得这是生活在正轨的状态。
出现一些问题,自己处理完成的时候,也会有种生活回归正轨的状态。

于是很多时候就会去思考,什么才是生活的正轨。
究竟我一直所感觉,所认同的生活正轨是什么。

在一次回寝室的时候,自己突然想通了这个问题。
所谓的生活正轨。

“自己能掌控自己的生活节奏,朝着目标稳步前进,进步明确的状态。”

换成游戏里的行话,就是“带节奏”。只是玩家就我一个,输了也不会复活。

在这种状态下,由于“把控”了生活的节奏,自己在处理事情,学习新东西,思考各类问题的能力都会有较大的提升。
这一点,在半年前准备做但最后没有讲出来的分享中,有所提及。


17年-对自己的新期待

在代码方面,希望能写出更好的代码,包括但不仅限于可读性强,效率高等。希望自己具备解决一些复杂Case的能力。

团队管理方面,希望自己能带好家园,给家园带来最新的,互联网公司的氛围。推动家园向专业化学生团队发展。
尽管南昌互联网土壤贫乏,家园依然要努力开出最美的花儿。

生活方面,希望自己能够多注意身体,多去运动,毕竟活着最重要。

感情方面,希望能够遇到自己的那个她。

2017 - 终将远方

带着2016年的热枕与对2017年的期待。
前方路漫漫,且行且歌!


如果你觉得我的文章对你有帮助,请支持我。让我写出更好的文章。

支付宝付款 微信付款

《数据库原理及应用开发》与我的学习

起因

打小开始,自己就比较喜欢计算机。
上大学之后又自学了C,Java,HTML/CSS/JavaScript等编程语言。也加入了校内的家园工作室,成为了一名前端工程师。
学习过程中,愈发觉得计算机基础的重要性,遂开始选课+蹭课+Mooc自学的路。
上学期末,非常幸运的选中了《数据库原理及应用开发》这门课。

对个人

对于个人而言,选择《数据库原理及应用开发》并非机缘巧合也非无奈之举。
自己之前因为业务原因,一直使用的是MongoDB等NoSQL数据库,做一些简单的CRUD的应用。
因此选修这门课,一方面为了补足计算机基础,另一方面则是业务需要,需要了解SQL数据库的使用。

学习这门课程,对我的帮助如下:

  1. 对数据库的基础概念有一定的了解,能够大致知道什么是数据库,能够用来干什么
  2. 能够对结构化查询语言(SQL)有一定的了解,能够写一些“增、删、改、查”的SQL语句或存储过程
  3. 对某一数据库产品(例如mysql、oracle获取SQL Server)有一些了解,知道其在标准SQL上的一些扩展,知道它的一些特性,熟悉其简单的安装、部署、使用

但自己在学习过程中,发现也有很多不足。

  1. 尽管知道数据库的基础概念,但很多概念了解的还不是很透彻
  2. 能够写出基本的SQL语句,但很多时候写出的SQL语句并不是很好
  3. 由于所从事职业的问题,与数据库接触较少,因此所学的大部分知识并不能投入于实战中

对所学专业的帮助

自己所学专业是人力资源管理,对于下面这句话,感觉深有体会……

关系型数据库遵循ACID规则

翻译成人力资源的话语就是。
人力资源政策与人力资源战略需要遵循AC原则。

1. A (Atomicity) 原子性

原子性在计算机领域很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。

而在人力资源领域,则是说人力资源战略在实行的过程中需要有“原子性”,在颁布人力资源战略和实行过程中,不可突然废弃,否则容易造成公司制度紊乱,人心不齐的现象。所以如果制订了人力资源战略,就需要实施下去,而不能半途而废。

2. C (Consistency) 一致性

一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。

而在人力资源领域,可以理解为人力资源政策需要向一致性看起。公司的目的是获取利润,而目标则各不相同,因此在更改政策时,不能破坏这种最基本的目的与约束,需要向公司的目标不断靠近。

独立性与持续性

由于人力资源战略会随着组织的发展而不断调整,因此独立性与持续性并不适用与人力资源管理。

NoSQL与NewSQL的发展

自己注意到,最近业界有在提一个新词,NewSQL。

NewSQL是OldSQL和NoSQL的改进。具体的功能点可以看这个:

而联想到人力资源领域。则想到了人力资源管理的发展。

从一开始最固化的人事管理,再到后期的人力资源管理,然后再到现在最新的人力资源三支柱模型。同样也是在变化且发展着的。

这里如果只提发展的话当然不够。
NoSQL与NewSQL的出现,都是为了解决切实的业务问题而产生的,并非空穴来风。而人力资源管理模式的变更,也是顺应实际业务需求与组织发展而产生的变革。

而这是大部分事物发展的本质。并非突然出现的“破坏式创新”,而是在原有事物基础上的改进与发展,从而更好的顺应现实生活的需要。

本文同步发表于我的博客,在线阅读请扫码。


如果你觉得我的文章对你有帮助,请支持我。让我写出更好的文章。

支付宝付款 微信付款

2016-编程元年

时光

时光荏苒,如白驹过隙。不知不觉,已是2016年的末尾。
一年来,发生了很多很多事情,足矣让我一人细细的怀念上一年。
值得庆幸的,就是这一年来所做的事情,懊恼、开心、遗憾等情绪都有。

但是,没有后悔啊……

魔幻

16年给我的最大感受,大概就是魔幻。
一切显得那么的不真实,但一切又是我所亲身经历的现实……
想过会实现很多事情,只是没想到自己真的一一达成,然后实现了。

编程元年

之前一直在想博客的标题,后面想了想,取了“编程元年”这个名字。
大概是这一年,都和编程紧密相关,自己也从一只前端刚入门的菜鸡,进化到了一个初级前端工程师。

做的事情和数据

这一年都做了什么,让数据来说话:

博客


开源项目

Commit


某个项目的:

技术栈

前端:

1. Vue + Vuex + Vue-Router
2. ES6/7
3. Gulp, Webpack

后端:

1. Node.js
2. Koa
3. TypeScript
4. Docker
5. MongoDB

App:

1. Android
2. React Native

读的书

读的书……没有细算,也基本无法算了。
一个月两三本的阅读量还是有的。
林林总总下来,几十本书吧。
交互、设计、前端、数学、人力资源管理,都会去看一看。

想说却不能说的那些

很多事情,想说。
但是不能说。
静静等待,积蓄能量。
借用三国演义动漫的一句歌词:

不鸣则已,一鸣动九天。

结语

很久没写博客了,很诧异每个月还有1.5k的访问量。写的文章现在也有人去挑错。很开心啊。
有想说的,但是想想其实也没什么好说的。
就这样吧~恢复写博客的好习惯~

2016-12-09 23:56 记于家园工作室机房


如果你觉得我的文章对你有帮助,请支持我。让我写出更好的文章。

支付宝付款 微信付款

Vue nextTick 源码解读

起因

自己第一次用Vue做项目时,经常遇到操作DOM的问题,但是很多时候因为Vue数据更新的特性,是不能在第一时间拿到更新后的DOM。
后面才观察到,Vue有一个nextTick方法。
nextTick的Api如下:

对于这句话:

将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。

自己感到十分好奇,因为之前我解决此类问题,使用的是setTimeout(fn, 0)的方式来的。
所以就继续打开Vue的源代码,细细研读。

异步更新队列

在Vue的文档中,异步更新队列部分有这么一段:

Vue.js 默认异步更新 DOM。每当观察到数据变化时,Vue 就开始一个队列,将同一事件循环内所有的数据变化缓存起来。如果一个 watcher 被多次触发,只会推入一次到队列中。等到下一次事件循环,Vue 将清空队列,只进行必要的 DOM 更新。在内部异步队列优先使用 MutationObserver,如果不支持则使用 setTimeout(fn, 0)。
例如,设置了 vm.someData = ‘new value’,DOM 不会立即更新,而是在下一次事件循环清空队列时更新。
为了在数据变化之后等待 Vue.js 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback) 。回调在 DOM 更新完成后调用。

那么由文档可知,异步更新队列的奥妙则在于MutationObserver
在MDN中,对MutationObserver的介绍如下:

MutationObserver给开发者们提供了一种能在某个范围内的DOM树发生变化时作出适当反应的能力.

而在Vue的源代码中,则是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* Defer a task to execute it asynchronously. Ideally this
* should be executed as a microtask, so we leverage
* MutationObserver if it's available, and fallback to
* setTimeout(0).
*
* @param {Function} cb
* @param {Object} ctx
*/
export const nextTick = (function () {
var callbacks = []
var pending = false
var timerFunc
function nextTickHandler () {
pending = false
var copies = callbacks.slice(0)
callbacks = []
for (var i = 0; i < copies.length; i++) {
copies[i]()
}
}
/* istanbul ignore if */
if (typeof MutationObserver !== 'undefined' && !hasMutationObserverBug) {
var counter = 1
var observer = new MutationObserver(nextTickHandler)
var textNode = document.createTextNode(counter)
observer.observe(textNode, {
characterData: true
})
timerFunc = function () {
counter = (counter + 1) % 2
textNode.data = counter
}
} else {
// webpack attempts to inject a shim for setImmediate
// if it is used as a global, so we have to work around that to
// avoid bundling unnecessary code.
const context = inBrowser
? window
: typeof global !== 'undefined' ? global : {}
timerFunc = context.setImmediate || setTimeout
}
return function (cb, ctx) {
var func = ctx
? function () { cb.call(ctx) }
: cb
callbacks.push(func)
if (pending) return
pending = true
timerFunc(nextTickHandler, 0)
}
})()

解读一下,这是个自执行函数。在MutationObserver存在的情况下,则是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var callbacks = []
var pending = false
var timerFunc
function nextTickHandler () {
pending = false
var copies = callbacks.slice(0)
callbacks = []
for (var i = 0; i < copies.length; i++) {
copies[i]()
}
}
var counter = 1
var observer = new MutationObserver(nextTickHandler)
var textNode = document.createTextNode(counter)
observer.observe(textNode, {
characterData: true
})
timerFunc = function () {
counter = (counter + 1) % 2
textNode.data = counter
}
const nextTick = function (cb, ctx) {
// 如果ctx参数存在,则为回调函数绑定this
var func = ctx
? function () { cb.call(ctx) }
: cb
callbacks.push(func)
if (pending) return
pending = true
timerFunc(nextTickHandler, 0)
}

核心的部分为:

1
2
3
4
5
6
7
8
9
10
var counter = 1
var observer = new MutationObserver(nextTickHandler)
var textNode = document.createTextNode(counter)
observer.observe(textNode, {
characterData: true
})
timerFunc = function () {
counter = (counter + 1) % 2
textNode.data = counter
}

在调用observe时,传入的参数有:

因为Mutation Observer则是异步触发,DOM发生变动以后,并不会马上触发,而是要等到当前所有DOM操作都结束后才触发。
调用timerFunc时,因为DOM操作已经结束,此刻触发注册的回调,就能获取到更新后的回调。

队列更新

在看文档时,也有注意这句话:

Vue.js 默认异步更新 DOM。每当观察到数据变化时,Vue 就开始一个队列,将同一事件循环内所有的数据变化缓存起来。如果一个 watcher 被多次触发,只会推入一次到队列中。等到下一次事件循环,Vue 将清空队列,只进行必要的 DOM 更新。

队列更新的实现则在于Mutation Observerpending状态的配合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var pending = false
function nextTickHandler () {
pending = false
var copies = callbacks.slice(0)
callbacks = []
for (var i = 0; i < copies.length; i++) {
copies[i]()
}
}
const nextTick = function (cb, ctx) {
// 如果ctx参数存在,则为回调函数绑定this
var func = ctx
? function () { cb.call(ctx) }
: cb
callbacks.push(func)
if (pending) return
pending = true
timerFunc(nextTickHandler, 0)
}

在这里,pending = true时代表正在等待所有的DOM操作结束,等待操作结束时调用nextTick传入的回调,将会被推入队列。从而实现DOM更新后,才触发某个队列的回调。
回调触发时,pending将被设为false, 队列也将被清空,从而继续实现队列功能。

setTimeout

既然看到了Mutation Observer,源代码中又有setTimeout(fn, 0)
就必须解释下setTimeout(fn, 0)的作用。这个涉及到了JavaScript的EventLoop,还是挺有意思的。
继续看MDN的解释:

零延迟 (Zero delay) 并不是意味着回调会立即执行。在零延迟调用 setTimeout 时,其并不是过了给定的时间间隔后就马上执行回调函数。其等待的时间基于队列里正在等待的消息数量。

因此,每次调用setTimeout(fn, 0)时,DOM的操作已经完成。确保获取的是更新后的DOM。

setImmediate

在Node.js中,有个setImmediate的Api。

在Node.js的Api中,解释如下:

1
2
3
4
setImmediate(callback[, ...arg])#
callback <Function> The function to call at the end of this turn of the Node.js Event Loop
[, ...arg] Optional arguments to pass when the callback is called.

作用也和setTimeout(fn, 0)类似。

结语

很早之前就想写这篇文章,但是因为各种事情,一直拖到了现在。
今天抽空,一口气写了出来。也算是自己对之前知识的总结。

参考资料:

Vue - 异步更新队列
HTML5新特性之Mutation Observer
MDN - 事件循环
Node.js - setImmediate


前端路漫漫,且行且歌


如果你觉得我的文章对你有帮助,请支持我。让我写出更好的文章。

支付宝付款 微信付款

Ning - JSConf

起因:

在知晓JSConf2016举办消息的那一刻起,心中便是无限期待。
期待着自己有一个也能参加JSConf这种JS开发者的盛会。
而当时则是受限于自己的财力,票价虽然只要500,但是对于学生而言,还是较难承担的。
很幸运的是在JSConf门票开售时,自己抢到了早鸟票。同时因为拿到的暑期实习Offer,资金问题也解决了。

大会两日

大会两日,各种分享不断。然后几乎云集前端大牛。平时只能在书里看到的,今天也是在现场看见了。
至于分享的质量,作为一个初学者,自然是不好评论的。
但是可以说的是,有些地方广告还是有点多。
第一天的主持人也是非常有趣。
领取到最有意思的奖品,应该是WiredCraft的一份贴纸,不是firefox而是waterfox

遇见贺老 && fix 人生 BUG

在大会第二天的下午,看到了贺老一个人坐在会场边上。便壮着胆上去交流和感谢了一番。
感谢是因为在我16年寒假准备深入学习前端一些知识时,看到了贺老在知乎上的回答:

才大二,少做(react/angular/php)hello world级别的事情(除非你能作出点真的有点实际价值的产品),先打基础。

当时觉得十分受用,后续也是按照他所说的去做了。后续则受益颇多。
此次在会场看到了真人,自然是要表达一番感谢的。

后续则是向贺老询问了学习和学习方向上的一些问题。
而贺老的一番回答,对于此时的我则有醍醐灌顶之感。
下面是问题与回答的实录(加了些语气助词):

Q: 贺老您好,就我现在一半时间写Node.js,一半时间写前端。这样感觉自己没有一个侧重的点,也不知道自己往哪里发展比较好。感觉时间和精力分配上出现了矛盾。

A: 没事,你还是学生,两个都学就可以了。你现在的功利心不要那么强,不要总想着学什么是有用的,学什么又是没用的。我做工程师那么多年,很多之前学过的东西都已经不用了,比如我当年花了一个暑假,才学会DOS系统的那一串指令。想想对现在的自己有用吗?很显然是没有的。但是编程就是这样,你学的很多东西都是会被淘汰的,所以功利心不要那么强

Q: 贺老,我现在只是学一门JS语言,因为前端啥都能做,所以也没打算换。但是我担心自己只学习一门语言还不够,需要再去学另外一门吗?

A: 当然可以学习啊。但是还是和我之前给的建议一样,既然你希望学习一门新的语言。就不要停留在Hello World的层面,而是要深入的去学习和使用它。这样你才能得到真正的收获。

Q: 贺老,我是自学前端的,现在也在补习计算机专业的基础课。您看有什么我在大学期间需要特别侧重的课程吗?

A: 如果可以的话,我建议你去把计算机专业的基础课都去上一遍。因为接触的越多,你的视角就越宽泛。你学一个东西,并不一定你一定就要去写出它。比如说算法,你知道常用的算法与时间复杂度,空间复杂度的计算。在遇到问题的时候,就知道选用何种算法去解决它。如果是在需要自己写的时候,也可以翻书再看看。但是这些如果你没有去学习,遇到问题时可能就没有这种思路。

Q: 谢谢贺老,我能和您拍张照,合影留念吗?

A: 当然可以,对于我来说,能帮你们这些年轻的工程师就非常好了。

总结

贺老的回答,真真切切的解决了我的疑惑,由于功利心太重,做什么事情都要权衡一二。
但是回望这一年多编程的学习,写代码时也只有快乐。
所谓功利心,可能就是自己想用更短的时间去写出更好的代码吧

与贺老的这一番面对面交流,是本次JSConf最大的收获了。

既然喜欢,去学就行,何必纠结那么多。

时夜,于回校列车上记录。


前端路漫漫,且行且歌。


如果你觉得我的文章对你有帮助,请支持我。让我写出更好的文章。

支付宝付款 微信付款

Event之构造自定义事件

起因

之所以写这篇博客,要追溯到16年寒假时,学习前端时产生的疑惑。
众所周知,在移动端点击事件是有300ms的延迟的。
而为了解决这个问题,各种方法层出不穷。
比较有名的有zeptotap事件。
它可以向下面这样调用:

1
$(element).on('tap', handler)

这种方式我当然还能理解,用zeptoon方法而已。
然后直到我看到了下面这种调用方式:

1
2
const element = document.querySelector(selector)
element.addEventListener('tap', handler, capture)

当时虽然年少,却也知道原生事件中,是不存在tap的。
于是兴趣在一瞬间被调用,开始了探寻之旅。
还记得当时大概折腾了有好几天,至于探寻和折腾的结果,就和下面图片说的一样。

2016-08-23_13:29:12.jpg

自定义事件这个问题,从寒假开始,一直困扰到今天。
基本每个月,我都会想起这个问题,然后尝试去解决。
然后重复得到“是在下输了”的结果。
现在想想,只是因为当时自己找的资料不对,然后一直看别人的源代码,但是源代码里加了很多兼容处理的东西。于是添加tap事件的核心代码就这样被淹没在里面。

意外之喜

今天在MDN找资料时,意外的看到了Event,本来只是想看看自己还有啥没写,或者遗漏的。
结果意外的发现了自定义事件的写法。有种本来只是瞎逛逛,却捡到了宝藏的感觉。

自定义事件

这儿借用MDN给的例子。来作为实例。

1
2
3
4
5
6
7
var event = new Event('build')
// Listen for the event.
elem.addEventListener('build', function (e) { ... }, false)
// Dispatch the event.
elem.dispatchEvent(event)

这样看起来,确实简单。
一个自定义事件,只要做三件事情即可。

构造事件 -> 监听事件 -> 触发事件

结语

没啥好说了。具体的方法下面的参考资料里有。
之所以写这篇文章,也只是纪念下烦恼自己半年有余的BUG罢了。

参考资料:

MDN - Event

MDN- 创建和触发 events

前端路漫漫,且行且歌


如果你觉得我的文章对你有帮助,请支持我。让我写出更好的文章。

支付宝付款 微信付款

Koa源码阅读笔记(4) -- ctx对象

本笔记共四篇
Koa源码阅读笔记(1) – co
Koa源码阅读笔记(2) – compose
Koa源码阅读笔记(3) – 服务器の启动与请求处理
Koa源码阅读笔记(4) – ctx对象

起因

前两天终于把自己一直想读的Koa源代码读了一遍。
今天就要来分析Koa的ctx对象,也就是在写中间件和处理请求和响应时的那个this对象。
而这个this对象,也是和Express的重要区别之一。不用再区分req,res(虽然还是得知道),一个this对象就能调用所有方法。
在实际开发中,是非常便利的。

Koa1和Koa2的区别

在这儿则需要谈一谈Koa1和Koa2调用this对象的区别。
Koa1在调用时,使用的是this,而Koa2则是ctx。

1
2
3
4
5
// Koa1
app.use(function * (next) {
this.body = 'hello world'
yield next
})
1
2
3
4
5
// Koa2
app.use(async (ctx, next) => {
ctx.body = 'hello world'
await next()
})

使用方式,只是把this换成了ctx。
具体为什么出现ctx和next,之前的文章koa-compose的分析有写。

ctx对象的作用

这儿继续以Koa1为例,因为看得懂Koa1源代码的,看Koa2的源码自然也不难。
首先放上关键的源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
app.callback = function(){
var fn = co.wrap(compose(this.middleware));
var self = this;
return function(req, res){
res.statusCode = 404;
var ctx = self.createContext(req, res);
onFinished(res, ctx.onerror);
fn.call(ctx).then(function () {
respond.call(ctx);
}).catch(ctx.onerror);
}
};

在上一篇Koa源码阅读笔记(3) – 服务器の启动与请求处理中,我们已经分析了fn的作用。
而onFinished则会在请求完成时调用,剩下的则是调用中间件去处理响应。
同时var ctx = self.createContext(req, res);这一句,不看createContext这个函数,应该也能猜出它的作用。
之后的fn.call(ctx)则说明了中间件中this的来源。
在这儿不得不感叹一句,JavaScript的this真的是太灵活了,配合闭包,call,apply等,简直拥有无限魔力。

ctx对象的创建

贴出相关的源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var response = require('./response');
var context = require('./context');
var request = require('./request');
/**
* Initialize a new context.
*
* @api private
*/
app.createContext = function(req, res){
var context = Object.create(this.context);
var request = context.request = Object.create(this.request);
var response = context.response = Object.create(this.response);
context.app = request.app = response.app = this;
context.req = request.req = response.req = req;
context.res = request.res = response.res = res;
request.ctx = response.ctx = context;
request.response = response;
response.request = request;
context.onerror = context.onerror.bind(context);
context.originalUrl = request.originalUrl = req.url;
context.cookies = new Cookies(req, res, {
keys: this.keys,
secure: request.secure
});
context.accept = request.accept = accepts(req);
context.state = {};
return context;
};

虽然看上去有点绕,但是仔细看看,还是不难的。
之前说过,Koa的源码简洁,一共就4个文件。
除了主要的Application.js, 剩下就都是与请求和响应相关的了。

有趣的地方

这儿,因为每次都要创建并调用ctx对象。为了避免影响原有的context,request,response对象。
这儿采用了Object.create()来克隆对象。

2016-08-02_14:52:55.jpg

context.js

首先就来分析,最开始的context.js。
context的实现很简单,但有意思的地方在于delegate这个地方。
就如下图所示:
2016-08-02_14:45:30.jpg

我看了delegate这个源代码,功能是把context中相应的方法调用和属性读取,委托至某个对象中。
而不用自己一个一个的写apply,call等。

request, response

关于request和response,我这儿就不详细写了。
在这儿放一张图足以。

2016-08-02_14:56:29.jpg

实际上,request和response是通过getter和setter,来实现存取不同属性的功能。
另外,通过刚才说的delegate方法,则使用ctx对象时,便能自动通过getter和setter获取想要的内容。

结语

这一篇很简单,其实也没啥可以说的。
因为Koa除了中间件部分看起来复杂,其它地方还是很简洁明了的。
学习源代码的过程中,也发现了很多优雅的写法,算是开拓了自己的眼界。
从会写到写好,看来还要挺长一段时间的。


前端路漫漫,且行且歌。


如果你觉得我的文章对你有帮助,请支持我。让我写出更好的文章。

支付宝付款 微信付款

2016暑期学习计划

前端

2016-07-29_前端-1.png

Coursera

2016-07-29_10:36:39.jpg
2016-07-29_13:50:24.jpg

读书

2016-07-29_13:52:32.jpg
2016-07-29_13:53:08.jpg

英语

学习计算机词汇。目标量: 1k。
也就是暑期结束时,这儿应该是1420。
2016-07-29_Screenshot_2016-07-29-13-57-40-357_不背单词.png


如果你觉得我的文章对你有帮助,请支持我。让我写出更好的文章。

支付宝付款 微信付款