2016 年里做前端是怎样一种体验

2016 年里做前端是怎样一种体验

本文转载自 SegmentFault,英文原文在 How it feels to learn JavaScript in 2016
吾辈觉得颇为有趣,便转载了一下(也算是前端开发的悲哀之处了吧)
附:吾辈觉得至今为止,前端工具链仍然没有好太多,工具链过多导致配置复杂,入门难度极大。
附:现在都 2018 了,然而吾辈的公司现在还是用 jQuery,虽然吾辈目前在内部强推了 VueJS #笑哭
附:吾辈这里对内容添加了一些样式,便于阅读时不那么疲劳。

问:最近我接手了一个新的 Web 项目,不过老实说我已经好久没碰过这方面的代码了。听说前端的技术栈已经发生了极大的变革,不知道你现在是不是仍然处于最前沿的开发者阵列?
答:准确来说,过去俗称的写网页的,现在应该叫做 Front End Engineer,我确实属于这所谓的前端工程师。并且我才从 JSConfReactConf 面基回来,因此我觉得我觉得我还是了解目前 Web 前端领域最新的面貌的。
问:不错不错,我的需求其实也不复杂,就是从后端提供的 REST 风格的 EndPoint 来获取用户活动数据并且将其展示在前端界面上。并且需要以列表形式展示,同时,列表要支持筛选排序等操作,对了,还要保证前端数据和服务端保持一致。按照我现在的理解,我打算用 jQuery 来抓取与展现数据,你觉得咋样?
答:不不不,现在估计已经没多少人使用 jQuery 了吧。你可以试试 React,毕竟这是 2016 年了啊。
问:额,好吧,那啥是 React 啊?
答:这是个非常不错的源自 Facebook 的前端库,它能够帮你便捷地响应界面事件,同时保证项目层级的可控性与还说得过去的性能。
问:不错不错,那我是不是就可以用 React 来展示数据了呢?
答:话是这么说没错,不过你需要添加 ReactReact DOM 依赖项到你的页面中去。
问:等等,React 不是一个库吗?为啥要添加两个依赖呢?
答:不要急,前者是 React 的核心库,后面呢算是 Facebook 操作的辅助库,这样就能让你用 JSX 来描述你的界面布局了。
问:JSX?啥是 JSX
答:JSX 是一个类似于 XMLJavaScript 语法扩展,它是另一种描述 Facebook 的方式,可以认为是 HTML 的替代品。
问:等等,HTML 咋啦?
答:都 2016 了,直接用 HTML 早就过时了。
问:好吧,那是不是我把两个库添加到项目中我就可以使用 React 了?
答:额,还要一些小的工具,你需要添加 Babel 到你的项目中,这样你就能用了。
问:又是一个库?Babel 又是什么鬼?
答:你可以把 Babel 认为是一个转译工具,可以将某个特定版本的 JavaScript 转译为任意版本的 JavaScript。你可以选择不使用 Babel,不过那也就意味着你只能用烦人的 ES5 来编写你的项目了。不过既然都是 2016 了,我建议你还是使用最新的 ES2016+ + 语法吧。
问:ES5ES2016++?我已经迷茫了,ES5ES2016+ + 又是啥?
答:ES5ECMAScript 2015 的缩写,也是现在被绝大部分浏览器所支持的 JavaScript 语法。
问:ECMAScript
答:是的,你应该知道 JavaScript 最早于 1995 年提出,而后在 1999 年第一个正式版本定稿。之后的十数年里 JavaScript 的发展一直很凌乱,不过经过七个版本之后已经逐步清晰了。
问:7 个版本?那么 ES5ES2016+ 又是第几个版本呢?
答:是的,分别指第五个版本与第七个版本。
问:等等,那第六个版本呢?
答:你说 ES6?估计我刚才没有讲明白,ECMAScript 的每个版本都是向前兼容的,当你使用 ES2016+ + 的时候也就意味着你在使用之前所有版本的所有特性啦。
问:原来是这样啊,那为啥一定要用 ES2016+ 而不是 ES6 呢?
答:是的,你可以使用 ES6,不过如果你要使用 asyncawait 这些特性,你就要去用 ES2016+ 了。否则你就还不得不去使用 ES6Generator 来编写异步代码了。
问:我现在彻底迷糊了,我只是想简单地从服务端加载些数据而已,之前只需要从 CDN 加载下 jQuery 的依赖库,然后用 Ajax 方法来获取数据即可,为啥我现在不能这么做呢?
答:别傻了,每个人都知道一味使用 jQuery 的后果就是让你的代码变得一团乱麻,这都 2016 了,没人再想去面对这种头疼的代码了。
问:你说的是有道理,那现在我是不是就把这三个库加载进来,然后用 HTMLTable 来展示这些数据?
答:嗯,你可以选择一个模块打包工具将这三个依赖库打包到一个文件中。
问:额,啥是模块打包工具啊?
答:这个名词在不同的环境下指代也不同,不过在 Web 开发中我们一般将支持 AMDCommonJS 的工具称为模块打包工具。
问:AMDCommonJS 又是?
答:它们是用于描述 JavaScript 库与类之间交互的接口标准,你有听过 exports 与 requires 吗?你可以根据 AMD 或者 CommonJS 的规范来定义多个 JavaScript 文件,然后用类似于 Browserify 的工具来打包它们。
问:原来是这样,那 Browserify 是啥呢?
答:Browserify 最早是为了避免人们把自己的依赖一股脑放到 NPM Registry 中构建的,它最主要的功能就是允许人们将遵循 CommonJS 规范的模块打包到一个文件中。
问:NPM Registry
答:这是一个很大的在线仓库,允许人们将代码与依赖以模块方式打包发布。
问:就像 CDN 一样?
答:还是有很大差异的,它更像一个允许人们发布与下载依赖库的中心仓库。
问:哦,我懂了,就像 Bower 一样啊。
答:对哒,不过 2016 年了,同样没啥人用 Bower 了。
问:嗯嗯,那我这时候应该从 npm 库中下载依赖了是吧?
答:是的,譬如如果你要用 React 的话,你可以直接用 Npm 命令来安装 React,然后导入到你的项目中,现在绝大部分主流的 JavaScript 库都支持这种方式了。
问:嗯嗯,就像 Angular 一样啊。
答:不过 Angular 也是 2015 年的流行了,现在像 VueJS 或者 RxJS 这样的才是小鲜肉,你想去学习它们吗?
问:不急不急,我们还是先多聊聊 React 吧,贪多嚼不烂。我还想确定下,是不是我从 npm 下载了 React 然后用 Browserify 打包就可以了?
答:是的。
问:好的,不过每次都要下载一大堆依赖然后打包,看起来好麻烦啊。
答:是的,不过你可以使用像 Grunt 或者 Gulp 或者 Broccoli 这样的任务管理工具来自动运行 Browserify。对了,你还可以用 Mimosa
问:GruntGulpBroccoliMimosa?我们到底在讨论啥?
答:不方,我们在讨论任务管理工具,不过同样的,这些工具也是属于 2015 年的弄潮儿。现在我们流行使用 Webpack 咯。
问:Makefiles? 听起来有点像是一个 C 或者 C++ 项目啊。
答:没错,不过很明显 Web 的演变之路就是把所有事情弄复杂,然后再回归到最基础的方式。估计不出几年你就要在 Web 中写汇编代码了。
问:额,你刚才好像提到了 Webpack
答:是的,这是一个兼顾了模块打包工具与任务运行器的打包工具,有点像 Browserify 的升级版本。
问:嗷嗷,这样啊,那你觉得哪个更好点呢?
答:这个因人而异了,不过我个人是更加偏好于 Webpack,毕竟它不仅仅支持 CommonJS 规范,还支持 ES6 的模块规范。
问:好吧,我已经被 CommonJS/ES6 这些东西彻底搞乱了。
答:很多人都是这样,多了,你可能还要去了解下 SystemJS
问:天哪,又是一个新名词,啥是 SystemJS 呢?
答:不同于 BrowserifyWebpack 1.xSystemJS 是一个允许你将多个模块分封于多个文件的动态模块打包工具,而不是全部打包到一个大的文件中。
问:等等,不过我觉得按照网络优化规范我们应该将所有的库打包到一个文件中。
答:是的,不过 HTTP/2 快要来了,并发的 HTTP 请求已经不是梦。
问:额,那时候是不是就不需要添加 React 的依赖库了?
答:不一定,你可以将这些依赖库从 CDN 中加载进来,不过你还是需要引入 Babel 的吧。
问:额,我刚才好像说错了话。
答:是的,如果按照你所说的,你需要在生产环境下将所有的 Babel-core 引入,这样会无端端增加很多额外的性能消耗。
问:好吧,那我到底应该怎么做呢?
答:我个人建议是用 TypeScript+Webpack+SystemJS+Babel 这一个组合。
问:TypeScript?我一直以为我们在说的是 JavaScript
答:是的,TypeScriptJavaScript 的超集,基于 ES6 版本的一些封装。你应该还没忘记 ES6 吧?
问:我以为我们刚才说到的 ES2016+ + 就是 ES6 的超集了。为啥我们还需要 TypeScript 呢?
答:因为 TypeScript 允许我们以静态类型语言的方式编写 JavaScript,从而减少运行时错误。都 2016 了,添加些强类型不是坏事。
问:原来 TypeScript 是做这个的啊!
答:是的,还有一个就是 Facebook 出品的 Flow
问:Flow 又是啥?
答:FlowFacebook 出品的静态类型检测工具,基于函数式编程的 OCaml 构建。
问:OCamel函数式编程
答:你没听过吗?函数式编程高阶函数Currying? 纯函数?
问:我一无所知。
答:好吧,那你只需要记得函数式编程在某些方面是优于 OOP 的,并且我们在 2016 年应该多多使用呦。
问:等等,我在大学就学过了 OOP,我觉得挺好的啊。
答:是的,OOP 确实还有很多可圈可点的地方,不过大家已经认识到了可变的状态太容易引发未知问题了,因此慢慢的所有人都在转向不可变数据与函数式编程。在前端领域我们可以用 Rambda 这样的库来在 JavaScript 中使用函数式编程了。
问:你是不是专门一字排开名词来了?Ramda 又是啥?
答:当然不是啦,Rambda 是类似于 Lambda 的库,源自 David Chambers
问:David Chambers
答:David Chambers 是个很优秀的程序员,他是 Rambda 的核心贡献者之一。如果你要学习函数式编程的话,你还应该关注下 Erik Meijer
问:Erik Meijer
答:另一个函数式编程领域的大神与布道者。
问:好吧,还会让我们回到 React 的话题吧,我应该怎么使用 React 来抓取数据呢?
答:额,React 只是用于展示数据的,它并不能够帮你抓取数据。
问:我的天啊,那我怎么来抓取数据呢?
答:你应该使用 fetch 来从服务端获取数据。
问:fetch
答:是的,fetch 是浏览器原生基于 XMLHttpRequests 的封装。
问:那就是 AJAX 咯?
答:AJAX 一般指仅仅使用 XMLHttpRequests,而 fetch 允许你基于 Promise 来使用 AJAX,这样就能够避免 Callback hell 了。
问:Callback hell?
答:是的,每次你向服务器发起某个异步请求的时候,你必须要添加一个异步回调函数来处理其响应,这样一层又一层地回调的嵌套就是所谓的 Callback hell 了。
问:好吧,那 Promise 就是专门处理这个哩?
答:没错,你可以用 Promise 来替换传统的基于回调的异步函数调用方式,从而编写出更容易理解与测试的代码。
问:那我现在是不是直接使用 fetch 就好了啊?
答:是啊,不过如果你想要在较老版本的浏览器中使用 fetch,你需要引入 fetch Polyfill,或者使用 RequestBluebird 或者 Axios
问:来啊,互相伤害吧,你还是直接告诉我我还需要了解多少个库吧!
答:这可是 JavaScript 啊,可是有成千上万个库的。而且不少库还很大呢,譬如那个嵌了一张 Guy Fieri 图片的库。
问:你是说 Guy Fieri? 我听说过,那 BluebirdRequestAxios 又是啥呢?
答:它们可以帮你执行 XMLHttpRequests 然后返回 Promise 对象。
问:难道 jQueryAJAX 方法不是返回 Promise 吗?
答:请忘掉 jQuery 吧,用 fetch 配合上 Promise,或者 async/await 能够帮你构造合适的控制流。
问:这是你第三次提到 await 了,这到底是个啥啊?
答:awaitES7 提供的关键字,能够帮你阻塞某个异步调用直到其返回,这样能够让你的控制流更加清晰,代码的可读性也能更上一层楼。你可以在 Babel 中添加 stage-3 preset,或者添加 syntax-async-functions 以及 transform-async-to-generator 这两个插件。
问:好麻烦啊。
答:是啊,不过更麻烦的是你必须先预编译 TypeScript 代码,然后用 Babel 来转译 await
问:为啥?难道 TypeScript 中没有内置?
答:估计在下一个版本中会添加该支持,不过目前的 1.7 版本的 TypeScript 目标是 ES6,因此如果你还想在浏览器中使用 await,你必须要先把 TypeScript 编译为 ES6,然后使用 Babel 转译为 ES5
问:我已经无话可说了。
答:好吧,其实你也不用想太多,首先你基于 TypeScript 进行编码,然后将所有使用 fetch 的模块转译为 ES6,然后再使用 Babelstage-3 preset 来对 await 等进行 Polyfill,最后使用 SystemJS 来完成加载。如果你打算使用 fetch 的话,还可以使用 BluebirdRequest 或者 Axios
问:好,这样说就清晰多了,是不是这样我就达到我的目标了?
答:额,你的应用需要处理任何的状态变更吗?
问:我觉得不要把,我只是想展示数据。
答:那还行,否则的话你还需要了解 FluxRedux 等等一系列的东西。
问:我不想再纠结于这些名词了,再强调一遍,我只是想展示数据罢了。
答:好吧,其实如果你只是想展示数据的话,你并不需要 React,你只需要一个比较好的模板引擎罢了。
问:你在开玩笑?
答:不要着急,我只是告诉你你可以用到的东西。
问:停!
答:我的意思是,即使你仅仅打算用个模板引擎,还是建议使用下 TypeScript+SystemJS+Babel
问:好吧,那你还是推荐一个模板引擎吧!
答:有很多啊,你有对哪种比较熟悉吗?
问:唔,好久之前用了,记不得了。
答:jTemplates?jQote?PURE?
问:没听过,还有吗?
答:TransparencyJSRenderMarkupJS?KnockoutJS?
问:还有吗?
答:PlatesJS?jQuery-tmpl?Handlebars?
问:好像最后一个有点印象。
答:Mustache?underscore
问:好像更晚一点的。
答:Jade?DustJS?
问:不。
答:DotJS?EJS?
问:不。
答:Nunjucks?ECT?
问:不。
答:Mah?Jade?
问:额,还不是。
答?难道是 ES6 原生的字符串模板引擎。
问:我估计,这货也需要 ES6 吧。
答:是啊。
问:需要 Babel
答:是啊。
问:是不是还要从 npm 下载核心模块?
答:是啊。
问:是不是还需要 BrowserifyWebpack 或者类似于 SystemJS 这样的模块打包工具?
答:是啊。
问:除了 Webpack,还需要引入任务管理器。
答:是啊。
问:我是不是还需要某个函数式编程语言,或者强类型语言?
答:是啊。
问:然后如果用到 await 的话,还需要引入 Babel
答:是啊。
问:然后就可以使用 fetchPromise 了吧?
答:别忘了 Polyfill fetch,Safari 目前还不能原生支持 fetch
问:是不是,学完这些,就 OK 了?
答:额,目前来看是的,不过估计过几年我们就需要用 Elm 或者 WebAssembly 咯~
问:我觉得,我还是乖乖去写后端的代码吧。
答:Python 大法好!