Node即学即用第1章:基础入门_Node即学即用第1章:基础入门试读-查字典图书网
查字典图书网
当前位置: 查字典 > 图书网 > 互联网 > Node即学即用 > 第1章:基础入门

Node即学即用——第1章:基础入门

Node功能强大,特别是它能在浏览器以外运行 JavaScript。本书将阐述这一功能为何如此重要,以及使用 Node的好处。首先来概述一下这些特性。 很多人将 JavaScript用在前端网站应用开发上。 Node.js将这一流行编程语言扩展到了更多的领域,特别是后端网站服务器开发。 Node有几个重要的特性值得我们关注。 Node是对高性能 V8引擎的封装( V8是 Google Chrome浏览器的 JavaScript引擎),通过提供一系列优化的 API类库,使 V8在浏览器之外依然能高效运行。比如,在服务器端开发程序常常需要处理二进制文件, JavaScript语言本身对此支持得不好,因此 V8也如此,而 Node的 Buffer类库提供了轻松操作二进制数据的方法。使用 Node,除了可以直接操作 V8的 JavaScript运行时状态,还能在开发上得到更多益处。 Node的一大特性是对高性能的追求。首先, V8采用了编译领域的一些最新技术,使得用 JavaScript等高级语言编写的代码在运行效率上能够接近用 C等底层语言编写的代码,并且开发成本有所降低。 其次, Node利用了 JavaScript的事件驱动( event-driven)特性来构建高度可扩展的服务器程序。 Node采用了事件循环(event loop)架构,让开发高效的服务器程序变得简单和安全。对比其他构建高性能服务器的架构, Node既保证了性能,又降低了开发难度。这是一个极其重要的特性。大家都知道开发多线程并行程序很困难,而且非常容易出错。 Node却巧妙地回避了这一难题,并且保持着令人惊讶的高性能。当然,任何方法都存在利弊得失,在后续章节中,将会详细讨论 Node在这其中是如何取舍的。 Node提供了一系列“非阻塞”函数库来支持事件循环特性。比如,把文件系统或数据库操作封装成事件驱动形式的函数接口。当对文件系统发起请求时,程序不需要闲置等待硬盘把文件读取出来。就像在浏览器中 onclick事件被触发后会自动调用代码一样,非阻塞函数会在它获得文件内容后通知 Node中的程序。这种方式让访问慢资源变得简单可扩展,这对 JavaScript程序员来说可谓驾轻就熟,甚至普通人也很容易掌握。 Node的强大特性还包括能在服务器端运行 JavaScript,尽管这样的特性并非 Node所独有。如果想在主流浏览器上运行自己的应用,我们除了 JavaScript之外没有什么其他选择。那么要想同一份代码在浏览器客户端和服务器间共享,也只能选择 JavaScript。现在出现了越来越多用 JavaScript编写的复杂网页应用(如 Gmail),如果能把越多的代码共享到服务器上运行,那么开发的成本也会越低。 Node为服务器端共享网页的 JavaScript代码铺平了道路,这是 PHP、Java、Ruby或 Python等其他编程语言无法提供的。虽然也有其他平台提供了在服务器端使用 JavaScript的手段,但 Node已经先声夺人,迅速成为这个领域的主流平台。 除了可以用 Node现有的库来构建应用外,开发者也可以轻松为其扩展新的库,这实在令人欣喜。正因为 Node很容易扩展,在 Node项目对外发布后,其社区便迅速涌现出大量扩展库。其中许多是连接数据库或其他软件的驱动接口,还有相当一部分是独立有用的软件。 Node社区也是非常值得称赞的。虽然其社区非常年轻,但已经罕见地受到许多开发者的热情关注。初学者和专家们都聚集在此项目上,使用它并反馈贡献到社区中,致力于把 Node社区建设成每个人都能够在其中快乐地探索、分享知识并获得支持的地方。 1.1 安装 Node.js 安装 Node.js是极其简单的事情。 Node能够运行在 Windows、Linux、Mac,以及 Solaris和 BSD等其他 POSIX系统上。 Node.js能够在以下两个地址获得:项目官方主页( http://nodejs.org)和 GitHub代码库( http://github.com/joyent/node)。你可以优先选择 Node主页上提供的稳定发布版。包含最新特性的版本托管在 GitHub上,供核心开发团队使用。任何人想获得一份拷贝也能从 GitHub上下载。虽然这些新特性通常很炫,但它们没有稳定版本那么可靠。 让我们从安装 Node.js开始。首先要从 Node主页下载最新发布的版本。在 Node主页上,找到下载的链接。本书印刷时的稳定发布版本是 0.6.131。Node主页提供了 Windows和 Mac的安装程序,以及源代码包。如果你在使用 Linux,可以选择从源代码安装,也可以使用常见的包管理程序( apt-get、yum等)。 Node.js版本号依照 C的习惯:主版本 .次版本 .补丁。稳定版本的次版本号是偶数,开发版本的次版本号是奇数。虽然不知道 Node什么时候会到达 1.0版本,但可以认定是在 Windows和 Unix版本合并成一个版本同时发布时。 如果你使用安装包,可以直接跳到 1.2节。若你采用源代码安装,需要首先进行解压。使用 tar命令,带上 xzf参数。 x参数表示解压(而不是压缩),z参数告诉 tar用 GZIP算法进行解压, f表示根据最后一个参数的文件名来解压(见例 1-1)。 例 1-1 代码解压 enki:Downloads $ tar xzf node-v0.6.6.tar.gz enki:Downloads $ cd node-v0.6.6 enki:node-v0.6.6 $ ls AUTHORS Makefile common.gypi doc test BSDmakefile Makefile-gyp configure lib tools ChangeLog README.md configure-gyp node.gyp vcbuild.bat LICENSE benchmark deps src wscript enki:node-v0.6.6 $ 下一步是根据你的系统进行配置。 Node.js安装采用 configure/make方法。 configure程序将扫描你的系统,查找 Node依赖库的路径。 Node通常需要很少的依赖库。安装需要 Python 2.4或更高版本,如果你想使用传输层安全( TLS)或加密(如 SHA1),Node将需要 OpenSSL开发库。运行 configure程序将提示你缺少哪些依赖库(参见例 1-2)。 例 1-2 Node安装的配置 enki:node-v0.6.6 $ ./configure Checking for program g++ or c++ : /usr/bin/g++ Checking for program cpp : /usr/bin/cpp Checking for program ar : /usr/bin/ar Checking for program ranlib : /usr/bin/ranlib Checking for g++ : ok Checking for program gcc or cc : /usr/bin/gcc Checking for gcc : ok Checking for library dl : yes Checking for openssl : not found Checking for function SSL_library_init : yes Checking for header openssl/crypto.h : yes Checking for library util : yes 注 1:翻译本书时,版本已经是 0.8.1了。——译者注 Checking for library rt : not found Checking for fdatasync(2) with c++ : no 'configure' finished successfully (0.991s) enki:node-v0.6.6 $ 接着是运行 make来编译项目(例 1-3)。这将在我们一直使用的源代码文件夹下编译出可执行的二进制文件。 Node会在编译过程中列出当前进行到第几步,以便查看。 例 1-3 运行 make来编译 enki:node-v0.6.6 $ make Waf: Entering directory '/Users/sh1mmer/Downloads/node-v0.6.6/out' DEST_OS: darwin DEST_CPU: x64 Parallel Jobs: 1 Product type: program [ 1/35] copy: src/node_config.h.in -> out/Release/src/node_config.h [ 2/35] cc: deps/http_parser/http_parser.c -> out/Release/deps/http_ parser/http_parser_3.o /usr/bin/gcc -rdynamic -pthread -arch x86_64 -g -O3 -DHAVE_OPENSSL=1 -D_ LARGEFILE_SOURCE ... [ 3/35] src/node_natives.h: src/node.js lib/dgram.js lib/console.js lib/ buffer.js ... [ 4/35] uv: deps/uv/include/uv.h -> out/Release/deps/uv/uv.a ... f: Leaving directory '/Users/sh1mmer/Downloads/node-v0.6.6/out' 'build' finished successfully (2m53.573s) -rwxr-xr-x 1 sh1mmer staff 6.8M Jan 3 21:56 out/Release/node enki:node-v0.6.6 $ 最后一步是用 make install来安装。首先,例 1-4演示了如何为系统下全部用户安装 Node程序。这需要你有 root账户或者有运行 sudo的权限。 例 1-4 为系统下全部用户安装 Node enki:node-v0.6.6 $ sudo make install Password: Waf: Entering directory '/Users/sh1mmer/Downloads/node-v0.6.6/out' DEST_OS: darwin DEST_CPU: x64 Parallel Jobs: 1 Product type: program installing deps/uv/include/ares.h as /usr/local/include/node/ares.h installing deps/uv/include/ares_version.h as /usr/local/include/node/ ares_version.h installing deps/uv/include/uv.h as /usr/local/include/node/uv.h installing out/Release/src/node_config.h as /usr/local/include/node/ node_config.h Waf: Leaving directory '/Users/sh1mmer/Downloads/node-v0.6.6/out' 'install' finished successfully (0.915s) enki:node-v0.6.6 $ 如果你想只安装到本地用户,或是不使用 sudo命令,需要在运行 configure的时候加上 --prefix参数,指定路径来代替默认安装(例 1-5)。 例 1-5 安装到本地用户 enki:node-v0.6.6 $ mkdir ~/local enki:node-v0.6.6 $ ./configure --prefix=~/local Checking for program g++ or c++ : /usr/bin/g++ Checking for program cpp : /usr/bin/cpp ... 'configure' finished successfully (0.501s) enki:node-v0.6.6 $ make && make install Waf: Entering directory '/Users/sh1mmer/Downloads/node-v0.6.6/out' DEST_OS: darwin DEST_CPU: x64 ... installing out/Release/node as /Users/sh1mmer/local/bin/node installing out/Release/src/node_config.h as /Users/sh1mmer/local/ include/node/... Waf: Leaving directory '/Users/sh1mmer/Downloads/node-v0.6.6/out' 'install' finished successfully (0.747s) enki:node-v0.6.6 $ 1.2 开始写代码 本节将介绍一些 Node开发的基础内容,为进一步学习做准备。 1.2.1 Node REPL Node是服务器程序,人们常常难以理解它也有和 Perl、Python、Ruby一样的运行时环境。所以通常我们称 Node.js为“服务器端的 JavaScript”,但这不能完全描述 Node.js本身。了解 Node.js的最佳方法是使用其提供的 REPL模式( Read-Evaluate-Print-Loop,输入 -求值 -输出 -循环),即交互式命令行解析器,它非常适合检验和学习 Node.js。你可以在 Node命令行解析器中试验本书提供的代码片段。此外,因为 Node是对 V8的封装,所以 Node命令行解析器也是用来轻松测试 JavaScript的理想方法。同时,当你想运行一个 Node程序时,可以用任何你喜爱的文本编辑器写好并保存成文件,然后运行 node filename.js。命令行解析器是极佳的学习和探索工具,但我们不会将其用在产品程序中。 让我们启动 Node命令行解析器,来个热身,试验一下 JavaScript吧(参见例 1-6)。在你的系统中打开命令行终端。我正使用 Mac系统的自定义命令行环境,所以你的系统提示可能会有所不同,但使用的命令应该是一样的。 例 1-6 启动 Node命令行解析器并尝试测试 JavaScript $Enki:~ $ node > 3 > 2 > 1 false > true == 1 true > true === 1 false 第一行代码返回的结果为 false。这个例子来自一个收集 JavaScript诡异和奇特特性的网站 http://wtfjs.com。 拥有一个实时的开发环境,你就有了非常好的学习工具,但你还需要了解 Node解析器的一些有用的功能,才能更好地使用它。它提供了以点号( .)开头的元命令。如 .help会显示帮助菜单, .clear会清除当前运行的内容, .exit将退出 Node解析器(见例 1-7)。其中最有用的命令是 .clear,它会清除内存中任何变量或闭包,而不需要重启解析器。 例 1-7 使用 Node解析器中的元命令 > console.log('Hello World'); Hello World > .help .clear Break, and also clear the local context. .exit Exit the prompt .help Show repl options > .clear Clearing context... > .exit Enki:~ $ 使用解析器时,输入变量的名称就会在终端上显示其内容。 Node会尝试智能地显示复杂对象,比如通过描述来反映对象的内部构造,而不是简单地将其当做普通对象来显示(见例 1-8)。主要的例外是显示函数,并非解析器无法显示函数内容,而是因为函数通常都很长,如果解析器把函数都展开,很可能会导致刷屏。 例 1-8 解析器设置并显示对象 Enki:~ $ node > myObj = {}; {} > myObj.list = ["a", "b", "c"]; [ 'a', 'b', 'c' ] > myObj.doThat = function(first, second, third) { console.log(first); }; [Function] > myObj { list: [ 'a', 'b', 'c' ] , doThat: [Function] } > 1.2.2 编写首个服务器程序 命令行解析器是我们学习和试验的好工具,而 Node.js最主要的应用是服务器程序。设计 Node.js的一个主要目的是提供高度可扩展的服务器环境。这是我们在本章开篇介绍过的 Node和 V8引擎有所区别的地方。 Node除了用 V8引擎来解析 JavaScript外,还提供了高度优化的应用库,用来提高服务器效率。比如说, HTTP模块是专为快速非阻塞式 HTTP服务器而用 C重新编写的。让我们看一下 Node采用 HTTP服务器的“ Hello World”经典例子(例 1-9)。 例 1-9 “Hello World”Node.js Web服务器 var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello Worldn'); }).listen(8124, "127.0.0.1"); console.log('Server running at http://127.0.0.1:8124/'); 这个示例代码首先通过 require方法把 HTTP库包含到程序中来。有许多语言都有包含其他库这一方法, Node用的是 CommonJS模块风格。 Node模块将在第 8章详细介绍,当前需要了解的是, HTTP库所具有的功能已经赋给了 http对象。 下一步,我们需要一个 HTTP服务器。 PHP等其他语言需要在类似 Apache这样的 服务器中运行,而 Node和它们不同,因为 Node本身就是 Web服务器。但这同样  意味着我们需要先创建该服务器。下一行代码调用 HTTP模块的一个工厂模式方法(createServer)来创建新的 HTTP服务器。新创建的 HTTP服务器并没有赋值给 任何变量,它只会成为存活在全局范围内的匿名对象。我们可以通过链式调用来初 始化服务器,并告诉它监听在 8124端口。 当调用 createServer的时候,我们传了一个匿名函数作为参数。此函数绑定在新创建服务器的事件监听器上进行 request事件处理。消息事件是 JavaScript和 Node的核心。在这个例子中,每当一个新的访问请求到达 Web服务器,它都将调用我们指定的函数方法来处理。我们称这类方法为回调( callback)。因为每当一个事件发生时,我们将回调监听此事件的所有函数。一个很恰当的类比是,你从书店预订一本书,等书到货时,书店会“回调”通知你去取。 例子中的回调函数有两个参数,一个是请求的对象( req),一个是响应的对象(res)。在回调函数中,我们调用了 res对象的几个方法,这将修改响应结果。例 1-9没有使用 req对象,但你通常会需要同时使用请求和响应对象。 首先我们必须调用 res.writeHead方法来设置 HTTP响应头,否则就不能返回真实内容给客户端。我们设置状态代码为 200(表示 HTTP状态代码“ 200 OK”),并且传入一段 HTTP头描述。在本例中,我们只指定了 Content-type。 在完成了 HTTP头后,我们可以写入 HTTP正文。在本例中,我们用一个方法来同时完成写入正文及关闭连接。 end方法将会关闭 HTTP连接。但因为我们同时还传入了一个字符串, end方法将在把此内容发送给客户端后才关闭连接。 例子的最后一行调用了 console.log方法。就像 Firebug和 Web Inspector支持的浏览器对应方法那样,它将在标准输出 stdout上打印信息。 让我们在 Node.js终端上运行此程序,并看看运行结果(例 1-10)。 例 1-10 运行“ Hello World”程序 Enki:~ $ node > var http = require('http'); > http.createServer(function (req, res) { > console.log('Server running at http://127.0.0.1:8124/'); Server running at http://127.0.0.1:8124/ node> 在这里我们运行 Node解析器,然后输入例子中的代码(我们不介意你从网站上进行复制粘贴)。Node解析器接受了代码,并用“…”提示你的输入未完成并等待补充完整。当我们运行到 console.log那行时, Node解析器打印出 Server running at http://127.0.0.1:8124/。现在我们可以在浏览器中访问“ Hello World”例子了(如图 1-1所示)。 图 1-1:在浏览器中访问“ Hello World” 跑起来了!虽然这不是一个惊人的演示,但我们只用了 6行代码就把“ Hello World”程序运行起来了。我们并不推荐这样的代码风格,但我们已经往前迈出第一步了。在下一章中,我们将看到更多的代码,但接下来我们先思考一下为什么 Node会发展成为现在这个样子。 1.3 为什么选择 Node 在写本书的时候,我们清楚地知道 Node.js是多么地新。许多平台要经历多年才被人们接受,而在 Node.js这一崭新的平台上,人们却展现了前所未有的热情。我们希望通过探究人们热衷于 Node.js的原因,帮助你找到能产生共鸣的特性。通过了解 Node.js的强项,我们能发掘出它最擅长的领域。本节将讨论是哪些因素造就了 Node.js,它为何能快速流行。 1.3.1 高性能 Web服务器 当我们在 10多年前第一次开始编写 Web应用的时候, Web还非常小。当然,期间我们经历了 .com泡沫。但那时从事互联网行业的人数还是相当少,创建的网站也没现在这么火热。时至今日,有了先进的 Web 2.0和随时随地可以上网的手机,这对我们这些开发人员提出了更多的要求。我们不但要提供更复杂、更多交互、更接近生活的功能,而且有越来越多的用户通过各种设备频繁使用这些功能,这是一个极大的挑战。硬件在持续改进,同时我们也需要提高软件开发水平来支持这些需求。如果只是单纯地采购更多的硬件来支撑新功能和新用户,就不那么划算了。 Node给 Web服务器程序开发领域引进了事件驱动编程,来尝试解决这一问题。实践证明,虽然 Node不是第一个尝试此方法的平台,但它是目前为止最为成功的平台,而且我们认为它使用起来也是最容易的。后续章节会详细分析事件驱动编程,在这里我们先对其进行简短的介绍。想象一下,你现在需要连接到一台 Web服务器上获取一个网页,这在正常的 DSL连接速度下通常需要花费 100毫秒左右。如果连接的是一台普通的 Web服务器,它会在服务器上为你的请求创建一个新的程序运行实例。该程序自顶向下运行(按顺序运行所有的函数)来响应请求并生成网页返回给你。这意味着该服务器在请求被满足前需要一直占用固定大小的内存,其中包括了把数据返回给你所要等待的 100多毫秒。 Node则不是采用此方式,而是在同一个程序内服务所有的用户。每当 Node需要等待一些费时的操作,比如等待确认你已经收到返回的数据时(好让它标记此请求已经完成),它就继续处理下一个用户的请求去了。我们对细节描述得还是太多了,但这些特性意味着 Node在内存处理上比传统服务器程序高效得多,也就是能够同时快速地服务更多的用户。这是个巨大的成就,人们也为此而热爱 Node。 1.3.2 专业的 JavaScript 人们喜欢 Node的另一个原因是 JavaScript。Brendan Eich在 1995年发明了 JavaScript语言,这是一门在 Netscape浏览器上使用的简单脚本语言。令人惊讶的是,自从 JavaScript出现以来,它已经不止运用在浏览器上了。早先 Netscape服务器程序就支持 JavaScript作为一门服务器端脚本语言(称为 LiveScript)。虽然 JavaScript当时并没有在服务器端得到广泛应用,却毫不妨碍它在快速发展的浏览器市场上大受欢迎。 JavaScript和微软的 VBScript展开了激烈竞争,都想成为 Web上的主流开发语言。很难说明为什么 JavaScript最终胜出,也许是因为微软允许 JavaScript运行在 IE浏览器上 2,也许是因为 JavaScript语言本身优势明显,无法不脱颖而出,总之它完胜了。于是,在 2000年初期, JavaScript已经成为 Web开发语言的代名词,不只是在浏览器开发 HTML的第一选择,而且是唯一的选择。 这和 Node.js又有什么关系呢?首先我们要记得当 AJAX革命发生,并且 Web风头正劲的时候(想想 Yahoo!、Amazon、Google等是多么风光),AJAX中“ J”的唯一选择就是 JavaScript,完全没有其他替代品。这导致整个行业急需大量优秀的 JavaScript程序员。 Web成为一个真正意义上的平台,并且附带着 JavaScript是其开发语言,这就要求我们这些 JavaScript程序员去提升自身能力。 JavaScript被视为程序员的第二或第三门编程语言,这本身就反映出人们对其重要性的重新认识。此时涌现出许多专家,他们的努力使 JavaScript越来越为人们所接受。 这一运动的带头人物当属 Douglas Crockford。他关于 JavaScript的文章和视频很受欢迎,帮助许多程序员发现了这门备受指责的语言中所隐藏的内在美。许多使用 JavaScript的程序员为了处理 HTML和 XML文档,把主要精力花费在了浏览器对 W3C DOM API的不同实现上。可悲的是, DOM可能是 API中最丑陋的,而且各款浏览器的实现又是那么地不一致和不完整。也难怪过去十年里许多程序员都没有把 JavaScript认作一门“严肃”的语言。最近, Douglas关于 JavaScript好处( the good parts)的论述让人们认识到这门语言虽有弊病,但仍存在许多宝贵之处,因而带动了此语言的振兴。 在 2012年的今天,有越来越多的 JavaScript专家倡导 JavaScript代码应当精心编写、高性能、易维护。 Douglas Crockford、Dion Almaer、Peter Paul Koch(PPK)、 John Resig、Alex Russell、Thomas Fuchs等许多专家对此进行了研究、提议和加工,其中最主要的是提供了程序库,这些程序库让全世界成千上万的专业 JavaScript 译注 2:IE浏览器并非真的支持 JavaScript或 ECMAScript,它支持的变种叫 JScript。近年来, JScript完 整地支持了 ECMA-Script 3,以及 ECMAScript 5的部分特性。同时, JScript还和 Mozilla的 JavaScript一样实现了一些专有的扩展,并且增加了某些非 ECMAScript标准的特性。 程序员能以追求卓越的精神去从事自己的行业。 jQuery、YUI、Dojo、Prototype、 Mootools、Sencha等许多程序库部署在各个网站上供大量用户每日使用。在 JavaScript不但被接受,还被广泛应用和拥护的环境下,这样的平台也许比 Web本身更为宽广。当这么多的程序员了解了 JavaScript时,这样的普及就成为了它的一个明显优势。 如果你在一屋子 Web程序员中调查他们使用什么语言,会了解到 Java和 PHP是最流行的, Ruby可能是目前次流行的(或者说至少和 Python流行程度相当),Perl则依然有许多追随者。但几乎可以肯定,任何从事 Web开发的人都使用过 JavaScript。虽然后端语言与浏览器直接割裂开来,但编程这事儿都脱离不了部署这一环节。各种各样的浏览器及浏览器插件允许使用不同的语言,但这些语言都不足以成为 Web开发的通用语言。现在我们面前有这样一个单一且通用的 Web开发语言,我们怎样才能把它放到服务器上去呢? 1.3.3 浏览器之战 2.0 在互联网初期,我们就经历了恶名昭著的浏览器之战。Internet Explorer和 Netscape在 Web功能上竞争激烈,他们分别在各自的浏览器上添加各种不兼容别人的编程特性,而且不支持其他浏览器所具备的功能。对于那些编写 Web程序的开发者来说,这些都是苦闷的来源,因为这使得 Web开发非常烦琐。 Internet Explorer或多或少成为了该轮竞争的胜者,变成了主流浏览器。几年之后,当微软在 IE6上裹足不前的时候,出现了一个新的竞争者:从 Netscape的旧成员中诞生的 Firefox。Firefox让浏览器市场风云再起, WebKit(Safari)和 Chrome紧跟其后。其中最有趣的还是在浏览器市场中新的竞争情况。 与浏览器之战的第一轮交锋不同,今天的浏览器主要争夺两个战场:一是坚持上一次浏览器战争后出现的标准,二是性能。随着网站越来越复杂,用户都想要最快的体验。这意味着,浏览器不但要很好地支持 Web标准和允许开发者进行优化,还要尽力在自己内部进行优化。以 JavaScript为核心模块的 Web 2.0时代, AJAX网站已经成为新的战场。 每个浏览器都有各自的 JavaScript解析器: Firefox的 Spider Monkey、Safari的 Squirrel Fish Extreme、Opera的 Karakan,最后还有 Chrome带来的 V8。这些解析器不断追求更快的性能,也为 JavaScript制造了创新的环境。为了让自己的浏览器突围而出,厂商们将尽最大能力让它运行得越来越快。

展开全文

推荐文章

猜你喜欢

附近的人在看

推荐阅读

拓展阅读

《Node即学即用》其他试读目录

• 序
• 前言
• 第1章:基础入门 [当前]