教科书里面的setTimeout

定义很简单
setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。

广泛应用场景
定时器,轮播图,动画效果,自动滚动等等

上面一些应该是setTimeout在大家心中的样子,因为我们平常使用也不是很多。

但是setTimeout真的有那么简单吗?

测试题

一个题目,如果你在一段代码中发现下面内容

var startTime = new Date();
setTimeout(function () {
    console.log(new Date() - startTime);
}, 100)

请问最后打印的是多少?
我觉得正确答案是,取决于后面同步执行的js需要占用多少时间。
MAX(同步执行的时间, 100)

再加一个题目,只有下面代码

setTimeout(function () {
    func1();
}, 0)
func2();

func1和func2谁会先执行?

这个答案应该比较简单,func2先执行,func1后面执行。

再来一题

setTimeout(function () {
    func1()
}, 0)

 setTimeout(function () {
    func1()
})

有什么差别?

0秒延迟,此回调将会放到一个能立即执行的时段进行触发。javascript代码大体上是自顶向下的,但中间穿插着有关DOM渲染,事件回应等异步代码,他们将组成一个队列,零秒延迟将会实现插队操作。
不写第二个参数,浏览器自动配置时间,在IE,FireFox中,第一次配可能给个很大的数字,100ms上下,往后会缩小到最小时间间隔,Safari,chrome,opera则多为10ms上下。

上面答案来自《javascript框架设计》

好了,看了上面几个题目是不是感觉setTimeout不是想象中那样了。

setTimeout和单线程

下面是我自己的一些理解
首先需要注意javascript是单线程的,特点就是容易出现阻塞。如果一段程序处理时间很长,很容易导致整个页面hold住。什么交互都处理不了怎么办?

简化复杂度?复杂逻辑后端处理?html5的多线程?

上面都是ok的做法,但是setTimeout也是处理这种问题的一把好手。

setTimeout一个很关键的用法就是分片,如果一段程序过大,我们可以拆分成若干细小的块。
例如上面的情况,我们将那一段复杂的逻辑拆分处理,分片塞入队列。这样即使在复杂程序没有处理完时,我们操作页面,也是能得到即使响应的。其实就是将交互插入到了复杂程序中执行。

换一种思路,上面就是利用setTimeout实现一种伪多线程的概念。

有个函数库Concurrent.Thread.js 就是实现js的多线程的。

一个简单使用的例子,引入Concurrent.Thread.js

Concurrent.Thread.create(function(){
    for (var i = 0;i<1000000;i++) {
        console.log(i);
    };
});
$('#test').click(function  () {
    alert(1);
});

虽然有个巨大的循环,但是这时不妨碍你去触发alert();

是不是很厉害~

还有一种场景,当我们需要渲染一个很复杂的DOM时,例如table组件,复杂的构图等等,假如整个过程需要3s,我们是等待完全处理完成在呈现,还是使用一个setTimeout分片,将内容一片一片的断续呈现。

其实setTimeout给了我们很多优化交互的空间。

如何使用

setTimeout这么厉害,那么我们是需要在在项目中大量使用吗?
我这边的观点是非常不建议,在我们业务中,基本上是禁止在业务逻辑中使用setTimeout的,因为我所看到的很多使用方式都是一些问题不好解决,setTimeout作为一个hack的方式。
例如,当一个实例还没有初始化的前,我们就使用这个实例,错误的解决办法是使用实例时加个setTimeout,确保实例先初始化。
为什么错误?这里其实就是使用hack的手段
第一是埋下了坑,打乱模块的生命周期
第二是出现问题时,setTimeout其实是很难调试的。

我认为正确的使用方式是,看看生命周期(可参考《关于软件的生命周期 》),把实例化提到使用前执行。

综上,setTimeout其实想用好还是很困难的, 他更多的出现是在框架和类库中,例如一些实现Promis的框架,就用上了setTimeout去实现异步。
所以假如你想去阅读一些源码,想去造一些轮子,setTimeout还是必不可少的工具。

微信公众号

前端修炼

个人经历

首先聊聊我code review的经历,当时刚刚来到百度,负责FE这边的高T是从Google过来的,听说他将很多Google那边的风格复制到了百度,其中code review就是重要的一块。

code review在我入职时,可以说是严格到令人发指,代码不通过无法提交,而且经常占用整个开发时间的大约40%。我当时的一段代码可以说经常被打回来5,6次。有时最终提交的代码都直接重构了当初的第一版。我也曾经因为code review,好几次差点耽误了开发进度。。

而现在我经常作为审核人员去review其他同学的代码,有时就感慨,由于项目的压力,现在没有以前那么严格的,但是code review我还是认为需要坚持下去的。

此外据我了解,即使在百度内部强制了code review,但是很多部门也没有完全执行。

review的目的

有和没有之间的态度差别
很简单,一段代码完成之后,有人看和没有人看,在质量上还是会有差别的。
当你知道你的代码会被人一行一行review时,你的代码一定为努力写的最好,而不是为了完成功能而应付了事,这就是态度上的区分。因为当你知道你写的代码是有人看的,你会更加在意你写的东西,你一定不想背后被人说,代码写的像一坨**。
而且确实我自己在review代码时,就能看出哪些为了赶上线而写的就和平常写的会有差别。

代码的可读,可维护
代码的可读和可维护在大团队很关键,最初我们代码审核为什么严格到令人发指,就是因为可读性和可维护性。
严格的code review可以感觉整个团队写出的代码就像是一个人写的。这样就是为了能让你随时切换到其他业务上,而且不需要什么适应时间。
可读性和可维护对于大型的多人合作系统,可以说非常关键,当一个团队30多人在一个单页面开发时,如果风格各异,代码仅仅符合功能和测试要求的话,你会发现多人开发的成本和新需求的升级的成本会越来越高。

举个常见的例子:
如果某个业务突然需要提高进度,这时的办法就是加人力,但是如果代码风格各异,加入的人力适应时间和学习成本是极高的,有时甚至不如保持原有人力去加班hold。要不就只能找些技术很强,可以无障碍学习的资深工程师江湖救急。

我们这边其实就是会出现上面项目突然加急的情况,但是,因为有code review,所以我们多人合作时,基本上可以保证1+1≈2的效率。为什么这么任性,就是因为在code review时已经控制了大家的写法和模式,让新加入的同学能够马上看懂以前逻辑并且做大概的业务了解就能上手了。
我这边最近就经历了这些,因为需要还一些历史遗留的技术债务,所以我需要调整底层的一些代码结构,这时保证功能和互相调用ok的情况下切换代码位置和路径就是我遇到的最大的障碍。
不过由于之前业务代码的高质量和开发模式基本上完全一致,所以我能很快找到统一的切入点,预先就能预估好可能会踩的坑。
如果没有code review之前严格的约束,我基本上需要每个业务功能去分析了,效率降到极低。

对于新人,快速引导,快速反馈
对于新人加入我们的团队,最快的上手方式就是,简单熟悉完之后,接手一个业务项目,然后我们会通过不断的code review给与开发方式,编码习惯,设计模式之间的反馈。
第一个项目的review 基本上会是最严格的。
其实对于技术人员,code review 就是用代码在做沟通。

及时发现非代码上的问题
有时我在review代码时会发现,有些地方经常在反复修改,或者有时实现会非常别扭。这时我就会问开发人员,是不是需求不明确导致的,是不是对需求的理由有偏差。
因为对于正在开发的同学,经常会陷入到业务具体的实现中,有时就是饶了很大的圈子但是自己确不知道。这时review时是能感觉到的,而且我也成功的多次阻止过。

对于效率的影响

很很多团队拒绝code review 主要是基于时间不允许,项目追的太紧之类的。
不过因为我也经历过没有code review的开发方式,我的感受是code review的影响不会有大家想的那么严重。

这里关键是具体如何去做

举例:
在开发一个新模块时,由于对于业务的开发模式不熟悉,上来就直接把功能什么的,需求什么的都搞定了。洋洋洒洒几千行代码的产出。最后需要提交时,review的人发现,我靠。。。这种实现不是我需要的,以后会埋很多坑啊。这时怎么办,重构?时间够吗,还是就这样了,把坑留给二期?

我们要求的code review不是上面那种,我们要求每次提交的内容尽量少,完成一个小的功能点就可以提交。这样review的人看起来也会越快,反馈的时间也会约迅速。
例如,完成目录结构和框架就可以提交一版,这时可以review文件名字起的是否合理之类的。
在每次提交代码的时间上,我们也是期望每天都会有提交,最长也不要超过3天,不然最后提交的代码对于review的人也是负担,出现的问题也不一定来得及修复。如果长期这样,确实是会影响到开发效率。

其实合理的code review即不用浪费很多时间,而且问题都能快速暴露,快速修复。代码始终都能在保证在一个正确的方向上。

微信公众号

前端修炼

最近一段时间,经常看到技术债务相关文章,最近也是参与了技术债务的清理。所以从参与者的角度介绍下遇到债务问题和对于技术债务的理解

其实在于前端领域,技术债务的相对较少,因为前端有一个特点就是随着功能和设计的升级,相对容易重构。

但是本文的背景是在一些大型的前端项目中

技术债务的产生

随着前端复杂度的增加,技术债务就开始慢慢的在浮现出来。特别是系统级别的单页面应用,功能不断的叠加,技术不断的更新,架构不断的升级,技术债务就暴露出来了。

举一个例子(如有雷同,表示慰问):
最开始尝试mvc时,使用了backbone开发单页面,然后一年后,发现angularjs特别火,而且调研发现这种mvvm模式更加提高效率,这时项目中一些新的模块开始都用上了angularjs,然后随着时间的推移,发现angularjs存在性能瓶颈,这时发现reactjs的虚拟dom和单向数据流很好,然后继续在新模块中引入。然后某一天,回头一看。。。WTF。。。发现架构混乱,维护困难,新业务开展困难等等。。。

如上面的例子,架构的升级,新技术的引入,特别容易引发技术债务的出现。
正如我之前的文章《如何在大公司成长》提到的,在成熟的系统中引入新技术其实是一个挑战非常大的事情,因为首先你必须控制好技术债务。
因为在厉害的架构师也无法设计一个面向未来可以一直不变的框架,再流行的模式也会不断演变。如果解决不好新旧的过度就很容易出现上面的情况。

可以直白的说,在越复杂的系统上面开发,就是带着越重的脚镣在跳舞。

再举一个例子,也是引发技术债务的一种情况:
由于进度的原因,不得不使用一些hack的方式(而不是从根源解决)去完成任务,然后在没有来得及删掉这种hack方式前,有其他人在你的基础上继续迭代和模仿,最后变得想去掉这种hack方式都去不掉。

技术债务的定义

什么样的问题称之为技术债务,我和网上观点有些不同。对于一些编程习惯,编码方式,有异味的代码等等,我认为这些应该属于代码素养的范畴,这些可以不断改善,而且完全可以小范围的重构解决,不会形成叠加效应。
我理解的技术债务是它的存在影响了整个系统的效率和阻碍了系统的发展,随着系统复杂度的增加,问题会不断的被放大。
下面一一说明,并且配合举例

技术债务的影响

影响日常的开发效率
我认为这个应该属于最严重的影响,由于债务的原因,严重拖慢了开发效率,导致开发人员开法困难。

举例:
两个模块共用一个修改组件,由于两个模块底层依赖不一样,导致需要重复开发两次。而且每一次需求升级,都是两次的重复开发。这种情况的结果直接导致人力成倍翻倍。

提高了开发人员的学习成本
这也是对于工程效率的影响,由于技术债务的积累,导致开发人员需要花更多的时间去理解开发任务,需要更多的时间学习理解。

举例
由于历史原因,同样一个组件/模块有两种实现方式,新同学在选择时第一感觉就是迷茫,乱,烦躁,不知所措,还需要花人力去了解哪个更加合适,哪个会有什么样的坑等等,如果选择错误了,还需要花无谓的时间重做。

持续的影响网站性能
债务的积累必定是一些遗留问题,特点就是随着时间,会越来越多,越来越复杂,越来越不敢砍掉。直接导致的问题就是,遗留代码太多,这些代码都是对线程的无谓消耗。最后的结果就是网站越来越慢

举例
控件最初使用的是1.0版本,换2.0时,由于旧的业务没有随着升级,就导致系统里面ui库多版本,这样,ui初始化就需要初始化两份,而且合并打包的时候,代码也会多出很多。

容易触发bug
旧代码的错误使用,或者使用不当,经常会导致一些莫名其妙的bug,而且极其难定位。

举例
在开发中不小心使用了旧代码的一些功能,而其他人员在清理或者修改重构时没有考虑,直接就会间接的产生bug。也是因为这种原因,旧代码也越来越不敢清理

成为了业务规划的瓶颈
由于一些架构因素,导致某些业务功能无法实现,或者实现起来的成本特别高。

举例
两个模块由于底层的技术架构不同,如果pm希望模块间有一些数据的互通,或者功能的互相调用,这种需求就是受到技术的限制而实现不了(当然可以通过一些hack或者非常规方式实现,但是每一次hack都是一次新债务的产生)

如何避免技术债务

技术债务能避免吗?
我觉得不可能,因为随着复杂度的增长,债务也在慢慢增长,只是快和慢的问题,也许你今天写的一个完美的功能,一年以后,对于新的架构就是一个债务,因为技术在不断再更新换代,没有任何一种模式是银弹。
如果非要有一种办法避免,我能想到的就拒绝新技术引入,一种模式坚持到底,但这肯定是不实际。

所以个人觉得对于技术债务
我们首先我们需要认识到债务的存在,最好有一个债务管理机制。例如有一个债务范围的控制,当影响面达到一定程度,就必须去清理。
其次认识到清理债务对当下的收益可能不明显,但是收益在未来会不断放大,所以对于债务的清理,我们必须要去面对,而不是逃避。
最后,还需要在平时的开发中,有技术债务的意识,例如,临时方案真的是临时的吗?开发出来的代码可维护吗?

微信公众号

前端修炼

下篇文章预告

聊聊code review

基本认识

开发环境和线上环境的区别

在很久以前,前端的部署其实比较简单,开发环境下,静态资源往服务器上面一扔就ok了,如果考虑下优化或者代码保护,也只是加一个代码压缩和混淆。没错,刚入行的时候我就是这么干的。。。

但是随着前端复杂度的发展,上面的做法已经无法满足需求了,特别是AMD,CMD概念的引入,打包合并就变成一项基本工作了。

举一个requirejs的例子,在一个复杂点的前端系统中,你能想象不打包直接上线吗,那样换来的可能就是打开首页就需要download几十个甚至上百个模块资源,这种行为是对网络资源的一种无谓消耗。所以对应requirejs有个r.js,就是专门消灭这种无谓请求消耗的,它做的事情也比较简单,按照一定规则,把各种模块合并成一个,这样在上线是一次请求就能download需要的所有js。

开发环境代码和线上代码区别

首先大家可以在构建时取消类似压缩,混淆这几部,可以观察下,构建完成后的代码,会和开发时你所写的有差别,开发环境的代码都经过了编译处理,根据一定的规则重新编译过。

举一个例子,我们在使用css3时,如果去自己写样式去适配chorme,safari,opera等等会累死。但是我们按照一个规则写一个,在构建时,代码自动做补全,是不是就很方便,能提高不少效率。

再举个例子,现在比较前沿的已经在开发环境下使用ES6了,但是想要在浏览器端直接运行还需要一段日子,但是没事,我们有Babel之类的工具,可以在编译时实现ES6到ES5的代码转换。这种用法我还没有用过,但是通过构建,我们可以用于尝试一些新的东西。提前做一些技术积累。

前端工程化核心环节

从前面两点大家应该能看出构建这一步的重要性了吧,可以说需要做到前端工程化,提高开发效率等,构建编译这一个步骤绝对是核心步骤之一。他的角色不逊色于搭建service,项目脚手架等等

具体举例

百度前端不仅有个fis(前端集成解决方案),还有一个edp,也是一个前端集成解决方法,主要是百度商业体系的前端在使用。
由于我们一直在使用edp,所以下面用edp举例去了解下前端构建

下面介绍一下我们自己系统中的一些使用

  1. 首先是js模块的合并,我们会按照首屏加载和可以懒加载的功能划分,将模块合并成整体,这样就避免了散文件的出现。首先散文件是有害处的,第一是,散文件可能没有版本号的区分,这样因为缓存导致bug;第二是散文件会严重拖慢性能,因为很多散文件不仅消耗请求资源,而且是在串行消耗。
  2. 将js用到的模板的合并,目的也是减少无谓的请求。
  3. 将less转换成css进行合并
  4. 将js文件压缩处理
  5. 将合并后的文件进行加上文件MD5版本号处理,MD5的目的就是基于文件内容解析出版本号,这样如果某个模块没有变更过,可以一直使用缓存,提高性能。
  6. 将合并后并且包含MD5的文件的path更新到首页html的require的config中
  7. 修改文件引用对应的path,因为类似于js引用的模板和css都需要更新到打包合并的path上
  8. 清理输出时的无用文件
  9. 添加版权信息等等

上面是一个基本流程,如果有特殊的需求,可以继续添加处理模块。
例如想引入reactjs,如果是构建时打包的话,我们肯定不希望上线的代码里面有一个browser.min.js文件,这样不仅增加了静态资源,而且增加了一个jsx翻译处理。那么我们可以在构建时增加一个jsx2js的步骤,这样就达到了,开发使用jsx,但是发布上线时,自动处理成了js代码。

关于性能优化

这种构建处理,我理解出发点都是从性能角度考虑的。
对于一线的业务开发过程,我们期望的是高效的开发业务,并不能把性能等等要求强加到业务开发中,不然我们业务开发是低效的,而且,随着性能优化策略的变更,我们无法随意的在业务中修改代码及时配合,就算是有人力修改,也可能导致bug。
所以将构建和业务解耦也是很关键的,只要业务开发符合某个规范,我们可以根据性能优化的点随时更新优化策略,构建代码的差别也是仅仅体现在性能上,而不会延生到业务中。

注意事项

大家可以看看前面几篇文章《如何避免工程效率陷阱》,《如何在大公司中成长》我们在拥抱前端工程化时,不要停留在使用阶段,也需要花点时间研究下原理,不然就很容易被工程了,因为你要相信未来前端的工程化只会让你的业务开发更加简单,关心的东西更少。

微信公众号

前端修炼

第一次听说生命周期这个概念还是在一次面试中,面试官让我说说一个框架的生命周期,然后。。。然后。。。面试就结束了

好吧,回到正题,生命周期是什么,百度百科上面搜一下生命周期软件生命周期 很多描述。
我所理解的生命周期就是一个事物的核心流程,例如:
一个小球从松开手到落地必然经过:向下加速,和地面的碰撞,反弹,停止等步骤,通俗的讲,这几个步骤就是小球落地的生命周期

生命周期的重要性

然而,生命周期对于我们的软件开发有什么用呢,对于前端,如果你只是做做交互,实现一些简单的功能,生命周期的需求其实不是那么强烈。
但是如果你使用一些复杂的框架,复杂的组件,你就会发现生命周期不管是在开发,修改,优化,还是在调试中都是一个关键的因素。

了解程序生命周期,就是了解程序的核心步骤,了解程序运行的几个关键节点。
外面比较流行的框架,流行的ui库(工具类除外)都会有清晰的生命周期,在他们的生命周期中,会告诉你,每一步会做什么,程序执行的过程中会暴露什么方法或者接口给你调用,告诉你哪一步适合哪种操作。当你熟悉了框架的生命周期,你才能更好的驾驭他,知道什么时候该做什么正确的事情,如何用正确的姿势销毁才不会导致内存泄露等等。

曾经有人告诉我,看框架的第一件事,就是去看他的生命周期,我很赞同。

假如你需要去造轮子,我觉得第一件事,也是梳理清晰核心流程(生命周期),然后开始设计,最后码代码。

框架的生命周期

直接举例子:

reactjs的生命周期
目前也在学习阶段,下面内容从一些介绍文章中总结而来
初始化阶段

  1. getDefaultProps
  2. getInitialState
  3. componentWillMount - 在render之前调用此方法,在render之前需要做的事情就在这里处理
  4. render - 渲染并返回一个虚拟DOM
  5. componentDidMount -在render之后,react会使用render返回的虚拟DOM来创建真实DOM,完成之后调用此方法

更新

  1. componentWillReceiveProps - 父组件或者通过组件的实例调用 setProps 改变当前组件的 props 时调用
  2. shouldComponentUpdate - 是否需要更新
  3. componentWillUpdate - 调用 render方之前
  4. render
  5. componentDidUpdate - 真实DOM已经完成更新

销毁阶段

  1. componentWillUnmount

了解上面的生命周期后,我首先能够保证我在基本的使用上不出大问题

我们使用的mvc框架er的一个模块的生命周期
下面是我自己总结比较详细的流程
初始化

  1. 调用enter方法开始生命周期
  2. 触发enter事件
  3. 使用createModel方法获取关联的Model对象
  4. 执行this.model.load()加载数据,并等待数据加载完毕
  5. 执行forwardToView方法开始处理View相关的逻辑
  6. 触发modelloaded事件
  7. 调用createView方法获取关联的View对象
  8. 触发beforerender事件
  9. 执行this.view.render()渲染视图
  10. 触发rendered事件
  11. 调用initBehavior方法
  12. 触发entercomplete事件

销毁

  1. 调用leave方法开始退出Action,会执行 this.model = null;this.view = null;
  2. 触发beforeleave事件
  3. 如果Model有dispose方法,则执行this.model.dispose()销毁Model对象
  4. 如果View有dispose方法,则执行this.view.dispose()销毁View对象
  5. 触发leave事件

正是上面这个清晰的流程图,我遇到问题时,一般都能比较准确的定位到问题出在哪里。不然只能靠盲目debugger去试和猜

生命周期的实际应用

  1. 首先是保证正确姿势的使用框架或者组件,不埋奇奇怪怪的坑,这个非常重要
  2. 调试bug时,通过观察出错的点发生在哪个流程中,可以快速缩小范围,而且经常会发现出问题的点就是在错误的节点处理错误的事情
  3. 生命周期的了解是阅读源码的基础,先了解了核心,再去关注细节实现

微信公众号

前端修炼

面试题

n个数中,n-1个重复偶数次,1个出现奇数次,怎么找出出现奇数次的那个数

这个问题是一个同事面试时问到的题目,我觉得很有趣,就拿来自己用了,题目的答案在最下面。

在看这个问题前,先聊聊一个前端面试一个问题
前端面试是否考察算法
大概2年前,我在微博上面看到两位大牛的争论:

@pureFE对@真阿当 说:阿当哥你好:我是一名在校学生,文科专业。前一段找实习的过程中注意到一些公司有算法要求。对于前端来说,专业知识的补习路线应该如何安排,应该像计算机专业那样从C、数据结构等等开始吗?对于前端开发者来说,专业知识应该达到何种程度才是合格?不知您能否指点一二,感激不尽!

@真阿当: 前端在实战中对算法和数据结构几乎没有要求,在你当下的境况学习这些知识对你找工作一点帮助也没有。前端开发的门槛低,所以有很多非科班出身的人从这个领域进入IT圈,你无需为“非科班出身”背上压力。为找工作的话,建议最快的路线是:先学css、后学一些基础js书……

@寒冬winter:100%反对。

回复@真阿当: 阿当你经常说前端工程师应该团结起来加强影响力,你就是这么让大家加强的么?没有算法能力,前端工程师怎么去实现新的交互效果?没有数据结构知识,前端工程师怎么处理大数据?没有这样的能力,前端怎么去承担更重要的职责?

@真阿当:算了,不争了,我该表达的都表达完了。求同存异。我的言论也只代表我个人看法,不保证一定是对的,各人有各人自己认同的发展路线。更倾向于哪种观点,决策权在诸位自己手上,冷暖自知谁也替不了你。不要动不动就“误人子弟”帽子扣下来,我担不起,也不想担。一家之言,说的是自己的真实感想。到此为止

@真阿当回复@糕富帅是我的人生理想:恩,是的,我说过要想前端能走得远一些,至少用原生js锻炼半年以上。我说的是“如何成为一个高级工程师”,而不是“如何跨入门槛”。绝大多数公司在面试时只会看这个人“在这个领域的基本功”怎么样,过不了这一关,跨不过入行的门槛。所以要先学会怎么通过面试。

@寒冬winter:目前为止我好像没听说哪个前端因为学习计算机基础知识耽误了专业技能,从当年51js我认识的人来看,基础好的无一例外几年后立于行业顶点,而那些”顺应市场”的人,不知去了哪里。实际上,这只关乎人的素质,舍弃了基础节约的时间并不能用于其它知识或者英语。

我这边的答案也是需要的,直接举一些例子:

  1. 最近很火的框架reactjs,他的核心就是实现了一个虚拟dom,每次页面的更新都能通过虚拟dom计算出最小变更内容,从而达到页面高效的刷新,实现最小diff的算法很关键

  2. 腾讯在手机web上实现了利用localstorage存储js,然后js实现增量更新的算法,达到每次刷新仅仅请求变更了的js内容,这样就解决了手机端流量宝贵和网速慢的问题,实现增量更新的算法很关键

  3. 我刚来百度时,组内有一位echart的贡献者,在一次组内分享中,一个大数据量储存的优化的问题,大概是下面这样的数
    [100001, 100002, 100003 …]
    在通过canvas绘图时,会比较费内存,然后他就使用时间换空间的方式处理如下
    [1, 2, 3 …] 设定base 是100000
    这样就解决了一定数据量内存过大的问题。

我觉得上面的例子就足够支撑算法在前端的重要性了,因为现在的前端不在仅仅是还原一些UI设计,做做交互了,实现一些功能了。
现在的前端越来越复杂,涉及面越来越多,向后延生可以利用nodejs去做服务端(全栈工程师);平行延生可以用react native去做native的开发;纵向延生,也会考虑webapp内存泄露,性能调优,打包编译,线上部署等等。
这些东西研究的越深,对于计算机基础知识的要求就越高,当然其中就包含了算法基础了。
那么问题来了,如果我们对于算法没有研究怎么办,其实我开始就是对算法没有什么研究,也不知道怎么运用在工作中,只是后来的工作中,慢慢发现自己对于计算机一些基础的匮乏,根据需要一点点补充的。
我一次在前端接触简单的算法是在看一个桌球游戏的源码时,游戏里面球的碰撞,反弹,加速度等,都是一些简单的计算和物理知识,挺有趣的
游戏github地址,我加了一些注释
https://github.com/tangguangyao/Snooker

回到面试题,我们可以聊聊这个题目为什么我觉得挺不错的

  1. 如果没有算法基础的人,如果思维不错,至少能够在一定时间内给出一个比较笨的解决方案,然后给与一些提示,能够引导到我期望的答案
  2. 对于有算法基础的人,能够大概说出几种解决方案,在我们余下的沟通中,回答一个我期望的答案,甚至更好的答案

微信公众号

前端修炼

答案
使用!(取非)的方式,出现第一次记录1,第二次回到0,第三次记录1…这样循环一次所有数,最后记录为1的就是我们需要的那个奇数

题记

牛逼的工程化架构可以通过简单重复的劳动来生产出复杂的产品

关于工程效率

最近几年关于前端工程化的东西特别多
grunt yeoman gulp 等等
百度自己的就有 edp fis 等等很多
利用这个东西,我们可以很快的在本地搭建开发环境,可以自动化打包编译,利用脚手架快速构建项目等

不管怎么样,这个些东西核心都是提高我们的开发效率

团队内的工程效率

抛开上面这些底层工具,在我们团队中,随着技术的成熟,也必然会产出一些提高团队开发效率的工具。
相对应的,团队内也会有几个技术资深的人在开发和维护这些工具

首先我们需要肯定工程是很好的,不管是从团队的角度还是前端的发展看。
对于团队,高效的工程化框架,可以把复杂的逻辑清晰的划分开来,让每位开发人员专注于业务点,学习成本降低

从react native介绍中,facebook就号称要让工程师入职第一天就能开发代码,能丢出这么牛逼的话绝对是有一个很牛逼的工程架构做支撑的

拿我们自己的table控件举例:
业务人员无需了解控件的内部逻辑,只需要根据使用文档配置好对应的参数即可,通过配置,控件自己实现了多选,单选,表头固定等等复杂功能
就算是做一些控件升级或者底层的替换,也做好了对于原有的api兼容。

类似这种控件/框架很多,也很好用,对于开发人员太友好了,开发起来太开心了

但是,脱离这套框架怎么办。。。

被工程化的特点

  • 对应现有的业务,换了框架不知道怎么入手
  • 不是工作业务内的一些技术点,需要比较高的学习成本
  • 对应新技术比较迷茫,不知道如何结合或者融入工作中

如何脱离被工程化

我觉得首先要有意识,不仅能够通过工程化架构生产出东西,也要计划好一层层梳理工程化架构的实现
参考如何在大公司中成长文中第二阶段。
在熟练使用框架以后,遇到问题是一定要自己去尝试解决问题,直接debug到框架的源码中,看看框架的运行流程,设计思路。
业务开发之余的时间也要从最常用的框架开始了解,多阅读源码等

最最重要的一点,意识,意识,意识,不要安于现状,被现有的工程死死框住

微信公众号

前端修炼

题记

来百度也快两年了,之前也经历了小公司,这里我想聊聊下如何在大公司里面成长,如何借助大公司的平台去提高技术。后面也有小公司的成长的一些建议

大公司的特点

  • 大公司的业务相对成熟
  • 大公司技术牛人多
  • 大公司会有自己的一套技术体系
  • 大公司分工明确
  • 大公司流程规范严谨

小公司的特点大家取个非就好了

大公司内部也有区别,例如:越重要,越成熟的业务,技术越偏保守

新人的成长阶段

第一阶段
目标:熟练使用公司框架
新人一般入职大公司后,基本上是从业务开始,先熟练的使用公司自己的技术框架开发业务。确保业务能够正常交付,并熟悉业务开发的一些流程,例如需求评审,开发,联调,提测,上线等等。

第二阶段
目标:弄懂框架技术原理
这个阶段研究(学习)公司自己的框架,弄懂原理,在遇到问题时,能够快速定位问题。这时技术上就是不只是停留在熟练使用框架上了,而是要懂框架,能够攻克一些业务上面的难点。
体现在工作上面就是,遇到一些比较难解答的坑时,第一时间不是去请教其他人,而是尝试自己去解决。

第三阶段
目标:反思框架的不足
在多次遇到框架的问题后,需要去发现现有框架的不足点,进而主动去学习外界的优秀框架。能够在技术框架,网站架构上面有自己的想法
这个阶段其实就是已经能够快速的定位和解决自己或者他人的问题了

第四阶段
目标:尝试推进新技术
这个阶段其实是非常难的,就是需要尝试推进新技术,提高网站性能和开发效率。回头看,在第三阶段的基础上,光有想法是不够的。对于越成熟的系统,你会发现,推进想法和技术会越艰难。因为需要考虑的内容实在太多,举个例子,如何和以往逻辑兼容,新老技术如何共存等等

第五阶段
目标:1.着眼于架构 2. 扩宽技术面
现在是时候能够改善技术框架,做一些对业务开发者透明的升级。把握系统的架构等事情了
并且在技术上不仅仅停留在前端,也是需要了解后端,部署,编译等等
整体上技术就是一个“T”字型,某一方面研究很深,同事眼界很开阔

第六阶段
我理解这个阶段其实就是大神级别了,这时就是总结一些东西,用于开源,推广,做一些前端的创新等等了

所以综上所述,希望成长的越快,其实就是尽量缩短每个阶段的时间。

如果在小公司呢?

其实小公司也能快速的成长,之前也是从小公司成长起来的
个人建议一:

  • 写博客
  • 坚持写博客

你会发现因为写博客被动push你一些技术的学习

个人建议二:

  • 关注一些牛人的微博和公众号,尽量能跟住他们的脚步

个人建议三:

  • 自己做些项目,用上学到的新技术
  • 关注github,优秀项目

个人建议四:

  • 小公司限制没有那么多,如果有什么好的项目,能用在工作中,就用吧

个人建议五:

  • 学会自己在网上找答案,小公司牛人相对少点,遇到比较坑的问题只能自己解决,但是相信我,每一次非常非常痛苦的解决完问题后,技术提升回报也是一样的

微信公众号

前端修炼

下篇文章预告

会聊一些大公司的工程效率陷阱,微信同步更新

简介

本文介绍下chrome的debug工具Profiles,很多人应该没用过,甚至不知道。

Profiles是什么

Profiles在哪里
如下图
前端修炼
没错,就在我们最长使用的导航里面,大家基本没有用到过吧。

Profiles具体可以干什么

定位性能问题,借助它我们可以

  • 可以借助Profiles定位出比较耗时的函数
  • 查找页面卡顿的原因

使用方法一

我们想查看点击一个按钮后,到展示页面的性能,我们可以

  1. 打开工具,如下图,点击start ,然后点击按钮
    前端修炼
  2. 完整内容展示后,点击stop(注意,中间不要有其他操作,避免干扰),然后就会生成一个性能分析的数据

实战
我们使用一段简单的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var test1 = function () {
var p = 0;
for(var i =0;i< 5000000;i ++) {
p = p + i;
}
console.log(p)
}
var test2 = function () {
var p = 0;
for(var i =0;i< 1000000;i ++) {
p = p + i;
}
console.log(p)
}
test1();
test2();

下图是生成的报告
前端修炼

使用方法二

使用

console.profile(name)console.profileEnd(name)

参数数是一个字符串,记录这次性能监控的名字

例如上面代码可以修改为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
console.profile('test')
var test1 = function () {
var p = 0;
for(var i =0;i< 5000000;i ++) {
p = p + i;
}
console.log(p)
}
var test2 = function () {
var p = 0;
for(var i =0;i< 1000000;i ++) {
p = p + i;
}
console.log(p)
}
test1();
test2();
console.profileEnd('test')

这样就能可以不适用人肉点击start和stop去记录。
这个命名为test的Profiles就是记录console.profile(‘test’)时间点到console.profileEnd(‘test’)时间点间的性能。

举一个实践中用到的例子

这个例子我也拿过来做过面试题,作为开放式题目:

我们在发出ajax时,打一个点作为开始,我们监听到ajax回来打第二个点作为结束,这两个点的时间是1000ms,但是我们通过network查看网络耗时,是300ms,请问中间700ms去哪里了?

其实这个问题我想了解两层,第一是js是单线程,阻塞;
第二个是如何定位问题,那么如果能借助这个工具分析,我就觉得很厉害了

微信公众号

前端修炼

摘要

今天整理一下我觉得不错,看过的javascript书籍

入门篇

《JavaScript DOM编程艺术(第2版)》
入门的好书,最开始接触javascript时,强烈推荐阅读

《精通JavaScript+jQuery》
这本书是我读的第一本js相关书籍,看了2-3遍,也很不错

进阶篇

《JavaScript高级程序设计(第3版)》
必须看,而且不能一开始就看,这本书最好是在使用了js一段时间,做了一些简单的项目,再看。
而且这本书,我当时至少看了3边,还做了笔记。
这本书每看一次,都会有不同的收获。

《javascript权威指南》
这本书,我没有买也没有看,不过很经典,还是推荐。
我觉得在我看了3遍《JavaScript高级程序设计(第2版)》 后(我当时看的时候是第二版),这本书其实可以不用怎么看。

高级篇

《JavaScript语言精粹》
这本书不错,不厚,但是很值得一读

《JavaScript设计模式》
讲设计模式的,对于大型应用,或者系统的开发,很有用。
对于设计模式,作为一个高级开发人员也是必须掌握的。

《JavaScript框架设计》
对于如何造轮子,轮子是怎么造的,很有帮助
对于一个想写框架的同学,这本书很好,也是国内的一个大牛写的

其他书籍

《编写可维护的JavaScript》
对于大型的团队协作,这个书很不错
没有什么技术难点,主要讲开发标准,开发习惯的
习惯这个东西其实很重要的

《javascript性能优化》
性能相关的,可以选择阅读

《基于MVC的JavaScript Web富应用开发》
这本书我看的比较早,那时候还刚刚开始推webApp,单页面应用
书籍讲mvc很好,只是现在mvc,mvvm比较流行了,也是选择阅读

nodejs

《深入浅出Node.js》
这本书不是入门的,对于nodejs入门,其实可以看看github项目
找几个网上的教材跟着做做,就好了
当做了几个项目后,在看这本书,就会发现能学到很多

html5,css3

零散的看过几本书,没有什么特别推荐的
主要看看api,了解下用法就行,主要看实战

非前端

《重构 改善既有代码的设计》
设计层面的

《编程珠玑》
《编程之美:微软技术面试心得》
刚刚入手的两本书
主要是想提高一些计算机基础知识用

微信公众号

前端修炼