全栈式 JavaScript 引见

如今,在建立一个Web运用的过程当中,你须要做出许多架构方面的决议设想。固然,你会愿望做的每个决议都是准确的:你想要运用能够疾速开辟的手艺,支撑连续的迭代,最高的事情效率,迅速,健壮性强。你想要字斟句酌而且充足迅速。你愿望你挑选的手艺能够在短时候和历久上都让你的项目取得成功。但这些手艺都不是易如反掌就能够选出来的。

我的履历通知我,全栈式JavaScript相符了这一切的要求。能够你已发明了些许端倪,又或许你已在斟酌它的实用性,而且在和朋侪议论争辩它的话题。然则你是不是亲身尝试过呢?在这篇文章中,我会关于全栈式JavaScript给出一个比较周全的引见,为何它会是准确的挑选,它又是怎样发挥它的魔法的。

先给出一个归纳综合预览:
《全栈式 JavaScript 引见》

接下来我会一项一项地引见这些组件。然则在这之前,我们简短地回忆一下,我们是怎样生长到如今的这个阶段的。

我为何挑选用JavaScript

从1998年最先,我就是一个Web开辟者。当时,我们运用 Perl 举行大多半的服务器端的开辟;然则从那时候最先,我们就在客户端运用JavaScript。Web服务器端的手艺已发作了天翻地覆的变化:我们被一波又一波的手艺潮水推着往前走,PHP,ASP,JSP,.NET,Ruby,Python,这里只列出了几个例子。开辟人员们最先意想到,在服务器端和客户端运用差别的言语使得事变变得庞杂化。

在初期的PHP和ASP的时期,那个时候模板引擎还仅仅是个想象,开辟人员们在HTML中嵌入他们的运用代码。我们常常能够看到下面这类剧本嵌入的写法:

<script>
    <?php
        if ($login == true){
    ?>
    alert("Welcome");
    <?php
        }
    ?>
</script>

或许更蹩脚:

<script>
    var users_deleted = [];
    <?php
        $arr_ids = array(1,2,3,4);
        foreach($arr_ids as $value){
    ?>
    users_deleted.push("<php>");
    <?php
        }
    ?>
</script>

关于新手来讲,很轻易被差别言语之间的用法而殽杂,犯下一些很典范的毛病,比方for和foreach。越发不爽的是,以如许的体式格局来写代码,使得服务器端和客户端很难以异常折衷的体式格局处置惩罚雷同的数据组织,纵然是本日也是云云(固然除非你的开辟团队有专职的前端和后端工程师 — 但纵然他们之间能够同享信息,但仍然不能仅仅基于对方的代码举行协作)。

<?php
    $arr = array("apples", "bananas", "oranges", "strawberries"),
    $obj = array();
    $i = 10;
    foreach($arr as $fruit){
        $obj[$fruit] = $i;
        $i += 10;
    }
    echo json_encode(obj);
?>
<script>
    $.ajax({
        url:"/json.php",
        success: function(data){
            var x;
            for(x in data){
                alert("fruit:" + x + " points:" + data[x]);
            }
        }
    });
</script>

最初,关于一致运用一种编程言语的尝试是运用背景的言语编写客户端的组件,然后编译成JavaScript。但这类体式格局并没有如希冀的一样很好地事情,许多相干的项目都失利了(比方被 ASP MVC 庖代了的 ASP.NET Web forms, 又比方正在逐渐被 Polymer 庖代的GWT)。固然这些主意都是巨大的,从本质上讲,都是想在服务器端和客户端运用统一种言语,让我们能够重用一些组件和资本(注重这里的关键词:资本)。

终究得出的答案很简朴:将JavaScript放到服务端

实在JavaScript降生之初是在网景公司的企业及服务器的服务端,只是当时它还没有完全准备好。经由数年的锻炼和错失,终究Node.js涌现了,它不仅将JavaScript放到了服务器端,同时也推行了非壅塞式编程(non-blocking programming)的头脑,这类头脑来自于nginx的天下。谢谢Node的创始者们nginx的手艺背景,而且继续(智慧地)坚持了它的简朴性,也谢谢JavaScript天生的事宜轮询机制。

(一句话归纳综合,非壅塞式编程目的在于将斲丧时候的使命放到一边,经由过程指定在这些使命完毕时须要做的操纵,如许能够在统一时候让处置惩罚器去处置惩罚其他的要求。)

Node.js永久性地改变了我们处置惩罚I/O接见的体式格局。作为Web开辟者,我们过去一向运用以下的体式格局接见数据库(I/O):

var resultset = db.query("SELECT * FROM 'table'");
drawTable(resultset);

这里的第一行代码本质上已壅塞了你的代码,由于你的代码停止下来守候数据库驱动返回一个效果集(resultset)。而与此同时,你的平台架构实在给你供应了并发的要领,一般是经由过程线程(threads)和派生(forks)。

在Node.js和非壅塞式编程的协助下,我们能够更多的掌握我们顺序的实行流。如今(只管在数据库I/O驱动器的背地能够已有并行实行),你能够定义你的顺序在I/O操纵时期并行做的事变,以及在接收到效果集以后做的操纵。

db.query("SELECT * FROM 'table'", function(resultset){
   drawTable(resultset);
});
doSomeThingElse();

上面的代码片断中,我们定义了两个顺序流:第一个在我们发出数据库查询以后实行的操纵,第二个是以回调的体式格局在我们接收到效果集以后做的操纵。这是一个异常文雅而且壮大的处置惩罚并发的体式格局。正如他们所说的,“一切都在并行实行——除了你的代码。(Evetything runs in parallel — except your code.)”如许,你的代码会更容易写,有更高的可读性,轻易明白,也便于保护,这些都基于你找回了对顺序流的掌握。

这些看法早就不是很新的看法,那为何他们跟着Node.js变得云云流行起来。很简朴:非壅塞式编程能够有多重完成的体式格局。但能够最简朴的就是运用回折衷事宜轮询。在大多半于言语里,做到这点并非一个简朴的事变。回调机制在其他的一些于言语里是一个比较罕见的功用,然则事宜轮询却不是。你会常常发明自身还须要在一些扩大库上做挣扎(比方,Python 中运用 Tornado)。

然则在JavaScript中,回调机制已被内建在言语中, 事宜轮询也是云云。而对JavaScript稍有相识的顺序员对它们也异常熟习(或许最少运用过它们,纵然他们有能够并不完全明白什么是事宜轮询)。突然之间,地球上一切的创业公司都能够在客户端和服务器端重用开辟人员(或许资本),处理了“须要Python巨匠(Python Guru Needed)”的雇用宣布题目

因而,如今我们有了一个生长迅速的平台(谢谢于非壅塞式编程),和一个异常易于运用的言语(谢谢JavaScript)。然则这就充足了吗?它是可连续的吗?我确信,JavaScript在将来会有一个异常重要的职位。下面我来通知你为何。

函数式编程

JavaScript是第一个将函数式范式带给公众的言语(固然,Lisp第一个涌现,然则大多半的顺序员都没有运用它开辟过一个能够作为产物的运用)。Lisp和Self,这两个深深影响了JavaScript的言语,充满了立异的理念,它们解放了我们的头脑,去发掘新的手艺,形式和范例。这些都连续到了JavaScript上。看一下 monads, Church number, 或许以至(作为更有实践性的例子)UnderscoreCollections functions,这些能够勤俭你一行又一行的代码。

动态对象以及原型继续

没有类(Classes),也没有无穷无尽的类条理组织的面向对象(Object-oriented)编程是供应了更疾速的编程体验——只需建立对象,增添要领然后运用他们。更重要的是,它大大减少了保护时重构的本钱,由于它许可顺序员直接修正对象的实例,而不须要修正类。这类速率和天真的体式格局为疾速开辟铺平了门路。

JavaScript就是互联网

JavaScript是因互联网而生的。它从一最先就涌现了,而且陪伴到如今。任何想要摧毁它的尝试都以失利而告终,比方Java Applets的式微,VBScript被微软的TypeScript(它终究会被编译成JavaScript)所庖代,以及Flash在手机市场以及HTML5上的一蹶不振。假如想不损坏不计其数个Web页面而庖代JavaScript是不能够的,所以我们接下来的目的应当是进步和完美它。这个事情,没有谁比ECMA的 Technical Committee 39 更适合了。

固然,JavaScript的替代者们天天都在降生,比方 CoffeeScriptTypeScript,以及成千上全能被编译成JavaScript的言语。这些替代者们在开辟过程当中或许是有效的(经由过程source maps),然则他们终究都不能够成功地替代JavaScript,两个重要原因:他们的社区永久不会比JavaScript更大,他们中的优异特征会被ECMAScript(也就是JavaScript)所吸取。JavaScript不是汇编言语,它是一个你能明白代码的高等编程言语——所以你应当明白它。

端到端(End-to-End)JavaScript:Node.js和MongoDB

我们已引见了为何要运用JavaScript。接着,我们来看看运用Node.js和MongoDB的来由。

NODE.JS

Node.js 是一个搭建疾速和可扩大的收集运用的平台——正如Node.js网站上所说。然则Node.js远不止这些:它是如今最火的JavaScript运转环境,被大批的运用和顺序库所运用——以至是浏览器的库代码也运转在Node.js上。更重要的是,这类服务器端的疾速实行让顺序员能够专注于更庞杂的题目,比方做自然言语处置惩罚Natural。纵然你并没有设想用Node.js来写你的服务器端运用,你也有能够运用基于Node.js的东西来革新你的开辟流程。举例来讲:用Bower来做前端包依靠治理,Mocha做单元测试,Grunt做自动化打包,以至用Brachets做全文代码编辑。

因而,假如你正准备开辟服务器端活客户端的JavaScript运用,你就须要对Node.js越发熟习,由于你在一样平常事情中会须要他。有一些很风趣的替代的挑选,然则它们中的任何一个的社区都不及Node.js的10%。

MONGODB

MongoDB是一个基于文档(Document-based)NoSQL数据库,它运用JavaScript作为它的查询言语(然则它不是用JavaScript写的),它完美了我们端到端的JavaScript平台。然则这个并非我们挑选MonoDB的重要原因。

MongoDB 是无形式的(schema-less),许可你以异常天真的体式格局把对象耐久化,因而能够迅速的应对需求变动。另外,它具有高度可扩大性,而且基于map-reduce,让它异常适合于大数据的运用。MongoDB云云天真,以至于它既能够用作无形式的文档数据库,也能够用作关联数据存储(只管它缺乏事件,只能经由过程模仿来完成),以至是用来缓存效果的键值对存储,就像 MemcachedRedis

基于Express的服务器端组件化

服务器端的组件化开辟一向不是一件轻易的是。然则 Express(和Connect)带来了“中心件(middleware)的头脑”。在我看来,中心件是服务器端定义组件最好的体式格局。假如你想找个熟习的形式来对照一下的话,那它异常接近于管道和过滤器(pipes and filters)。

基本头脑就是将你的组件作为管道的一部份。管道处置惩罚一个要求(也叫输入),天生一个效果(也叫输出),然则你的组件并不担任全部响应效果。相反,它只做它须要做的修正,然后将委派给下管道的下一节点。当管道的末了的节点处置惩罚完以后,这个效果再返回给客户端。

我们称这些管道的节点为中心件。很明显,我们能够建立两种范例的中心件:

  • 中心型(Intermediates)
    一个中心型节中心件理要乞降响应,然则它不负全权责全部响应,而是继续将它们分派给下一个中心件。
  • 闭幕型(Finals)
    一个完毕型中心件担任终究的响应效果。它对要乞降响应举行处置惩罚,以后不会分派给下一个中心件。但实践中,继续分派给一个中心件能够给架构带来更高的天真性(比方,以后须要增添其他的中心件),纵然下一个中心件并不存在(这类状况下,效果会直接被通报到客户端)。
    《全栈式 JavaScript 引见》
    (Large view)

取一个详细的例子,假定服务器端有一个“用户治理”的组件。依据中心件的体式格局,我们最好能有闭幕型和中心型的中心件。关于闭幕节点,我们要有建立用户和列出用户的功用。然则在我们做这些操纵之前,我们须要运用中心节点来做认证(由于我们不愿望没有认证过的要求能进来,以至建立用户)。一旦我们建立好了这些认证中心件,当我们想要把一个本来不须要认证的功用改变成认证功用的时候,我们只须要将这个中心件安插在响应的位置。

单页面(Single-Page)运用

当你运用全栈式JavaScript的时候,多半状况下你会专注开辟单页面运用。大多半的Web开辟者们都不由得不止一次地尝试着着手于单页面运用。我已建立了几个(多半为个人的),我置信他们就是Web运用的将来。你是不是在挪动链接上对照过单页面运用和一般的Web运用?他们在响应速率的差异有数十秒之多。

(注重:有些人能够差别意我的看法。比方Twitter,回滚了他们的单页面门路。与此同时,许多大的网站正在步入单页面时期,比方Zendesk。我已看到充足的证据证明单页面运用带来的优点,而且对此深信不疑。然则详细照样因状况而异。)

假如单页面运用云云壮大,那为何照样要挑选老土的体式格局来建立你的运用呢?我常常听到的一种争辩就是他们忧郁SEO(Search Engine Optimization)。然则假如你对此做了准确的处置惩罚,这将不是一个题目:你能够有多种处理体式格局,从运用无界面的浏览器(headless browser),比方PhantomJS,在检测到收集爬虫的时候衬着HTML,到运用一些现有框架实行服务器端衬着

基于Backbones.js,Marionette和Twitter Bootstrap的客户端MV*形式

关于运用MV*框架开辟单页面运用已有太多的议论了。只管很难挑选,然则我想说排名前三的是Backbone.js, EmberAngularJS

这三个都是异常被推重的,但哪一个是最适合你的

不幸的是,我必须得认可我在AngularJS上的履历有限,所以我就把它放在议论局限以外。那末,Ember和Backbone.js代表相识决统一题目的两种差别体式格局。

Backbone.js很小,然则适可而止的供应了建立一个简朴的单页面运用所须要的功用。另一方面,Ember是一个建立单页面运用的完全且专业的框架。它有更多的辅助东西,然则也有越发峻峭的学习曲线。(你能够浏览更多关于Ember.js的内容。)

基于你的运用的大小,能够简朴地经由过程比较“须要的功用”占“可用的功用”的比例来做出决议,它会给你很大的提示。

款式设想也同样是一个应战,然则再次,我们也能够列举出一些能够助我们一臂之力的框架。关于CSS,Twitter Bootstrap是一个异常好的挑选,它供应了一套完全的款式,它们能够马上运用,也异常便于自定义

Bootstrap是运用LESS言语建立的,它是开源的,我们能够依据我们的须要来修正它。陪伴它的另有一大堆用户友爱的组件,它们也有异常完美的文档。另外,一个定制化形式让你很方便地建立你自身的。毫无疑问,它恰是这个事情所须要的准确的东西。

最好实践:Grunt,Mocha,Chai,RequireJS 和 CoverJS

末了,我们将定义一些最好实践,同时谈谈该怎样完成和保护它们。具有代表性的,我的处理方案,终究聚焦到几个东西上,他们自身都是基于Node.js。

MOCHA 和 CHAI
这些东西能协助你运用[测试驱动开辟形式(test-driven development)](http://www.agiledata.org/essays/tdd.html或许行动驱动开辟形式(behavior-driven development)来革新你的开辟流程,建立一些基本架构来治理你的单元测试,而且自动运转这些测试。

如今有大批的JavaScript单元测试框架,为何要用Mocha?简短的回复就是它即天真又完美。我来解释一下:

  • 用户界面(Interfaces)
    或许你习惯于测试驱动的顺序组和单元测试的观点,又或许倾向于行动驱动测试的运用describle和should来定义行动定义的理念。Mocha让你能够同时运用这两种体式格局。
  • 报表天生器(reporter)
    运转你的测试代码会天生测试效果的报表,你能够运用形形色色的reporter来格式化这些效果。举例来讲,假如你须要供应一个连续集成服务器信息,你能够找到一个report来做这些。
  • 没有指定断言库(Lack of an assertion library)
    这几乎不是一个题目,Mocha决议让你挑选自身要运用的断言库,从而给你更多的天真性。你有许多的挑选,这恰是Chai发挥技艺的处所。

Chai 是一个异常天真的断言库,它能够让你运用以下三中重要断言体式格局的任何一种:

  • assert
    这是来自老派测试驱动开辟的典范的assert体式格局。比方:
assert.equal(variable, "value");
  • expect
    这类链式的断言作风在行动驱动开辟中最为罕见。比方:
expect(variable).to.equal("value");
  • should
    这也是用在测试驱动开辟中,然则我更引荐expect,由于should常常听起来比较重复(比方,定义一个行动范例,”it (should do something…)”)。举例:
variable.should.equal("value");

Chai和Mocha能够无缝集成。运用这两个顺序库,你能够运用测试驱动,行动驱动活任何想得到的体式格局来写你的测试代码。

GRUNT

Grunt是你能够自动化你的build使命,包括简朴的复制粘贴和文件拼接,模板预编译,style言语(SASS和LESS)编译,单元测试(运用Mocha),代码搜检,以及代码最小化(比方,运用UglifyJS或许Closure Compiler)。你能够增添你自身的自动化使命到Grunt中或许搜刮registry,那边数百个插件可供运用(再次提示,挑选运用有优越的社区支撑的东西)。Grunt也能够监控你的文件,当发作更改时触发一些操纵。

REQUIREJS

RequireJS 听起来是基于AMD API的另一种加载模块的体式格局,然则我敢保证地通知你,它远远不止这个功用。运用RequireJS,你能够定义你的模块之间的依靠和条理组织,让RequireJS库帮你来加载他们。它还供应了一种异常轻便的体式格局来防止全局变量污染,经由过程在函数体中定义你的模块。这让模块能够重用,不像定名空间模块(namespaced modules)。试想一下:假如定义了一个类似于Demoapp.helloWorlModule的模块,你想把他改成Firstapp.helloWorldModule,那末你须要把一切援用到Demoapp定名空间的处所都做修正,才能让它变得可移植。

RequireJS还能让你拥抱依靠注入形式。假定你有一个模块须要用到主运用对象(单例)的一个实例。经由过程运用RequireJS,你意想到你不须要运用全局变量来存储它,你也不能运用一个实例作为RequireJS的依靠。所以,你须要在你的模块组织器中加载这个依靠。让我们看一个例子:

在main.js:

define(
      ["App","module"],
      function(App, Module){
          var app = new App();

          var module = new Module({
              app: app
          })

          return app;
      }
  );

在module.js

define([],
      function(){
          var module = function(options){
              this.app = options.app;
          };
          module.prototype.useApp = function(){
              this.app.performAction();
          };
          return module
      }
  );

注重,我们不能在module的定义中到场对main.js的依靠,不然我们会建立出一个轮回援用。

COVERJS

代码覆蓋率(Code coverage)是你测试的一个器量规范。正如它的名字所示,它能通知你当前的测试集覆蓋了你代码的若干部份。CoverJS经由过程检测你代码中的语句(而不是像JSCoverage那样看代码行)并天生一个检测过的版本的代码来丈量你的测试代码的覆蓋率。它也能够支撑对连续集成服务器供应连续报表天生。

总结

全栈式JavaScript并不能处理一切的题目。然则它的社区和手艺会率领你走很长一段路。运用JavaScript,你能够建立基于一致的言语的可扩大的,可保护的运用。毫无疑问,这是相对值得我们关注的。

原文链接: An Introduction To Full-Stack JavaScript
转载自: 伯乐在线Owen Chen

    原文作者:JeOam
    原文地址: https://segmentfault.com/a/1190000000355221
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞