ajax的盛行,使javascript成为前端开发人员的宠儿.现今js已经可以通过nodejs在服务器运行.本文将通过对一段代码的逐渐改进来展示如何让程序员使用javascript快乐得进行非阻塞异步编程.nodejs和mongodb的具体安装和使用方法请参考文章最后的参考文献列表.
Hello,Node !
nodejs是编程就绪的,任何功能都要通过编程实现.这和Tomcat,ApacheHTTP等运行就绪服务不同,后者安装后可以直接运行就可以通过浏览器访问.而nodejs起码要有如下代码.
var http = require('http'); http.createServer(function(req,resp){ resp.end('Hello , Node !'); }).listen(8124); console.log('server startup');
将这些代码保存为hellonode.js然后在命令行执行node hellonode.js.在浏览器通过http://localhost:8124/即可访问该服务,浏览器窗口会显示"Hello , Node !"字样.这段代码的意义很容易理解,开头的require相当于java中的import将http模块引入,后面使用http模块的API构建http服务.javascript回调用来处理收到的请求,并返回字符串给浏览器.
一个稍微复杂的例子
现实环境中,常规得处理http请求的过程大概是这样的.首先,服务器收到请求并从中解析出请求参数,然后使用这些参数进行数据库查询,最后将得到的结果放入模板生成视图响应给用户.伪代码大概如下这个样子.
var http = require('http'); var queryString = require('queryString'); var url = require('url'); var db = {};//初始化数据库 http.createServer(function (req, resp) { //1.解析请求参数 var params = queryString.parse(url.parse(req.url).query); var template = 'result = _'; //2.使用参数查询数据 db.query(params, function (err, result) { //3.在回调中使用查询结果 if (err) throw err; var view = template.replace(/_/, result); //4.返回视图,响应给客户端 resp.end(view); }); }).listen(8124); console.log('server startup');
变得更复杂
可以看到代码(2)部分由于数据库查询在node中是无阻塞的,所以必须将所有后续处理查询结果的代码作为回调来使用,上面代码的处理过程比较简单,但是如果放入真实的应用中,不一定如此,比如模板要根据请求参数从本地文件系统加载.代码就会变为如下样子.
var http = require('http'); var queryString = require('queryString'); var url = require('url'); var fs = require('fs'); var db = {};//初始化数据库 http.createServer(function (req, resp) { //解析请求参数 var params = queryString.parse(url.parse(req.url).query); //使用参数查询数据 db.query(params, function (err, result) { //在回调中使用查询结果 if (err) throw err; fs.readFile(params.path, function (err, template) { if (err) throw err; //填充模板 var view = template.replace(/_/, result); //返回 resp.end(view); }) }); resp.end('Hello , Node !'); }).listen(8124); console.log('server startup');
深层嵌套问题
可以看到由于异步编程所以难免产生了又一层的嵌套回调.可以想想当处理过程更复杂的时候,会产生像如下的深层嵌套问题.
setp1(function (err, result1) { setp2(result1, function (err, result2) { setp3(result2, function (err, result3) { step4(result3, function (err, result4) { //更多的嵌套回调 }) }) }) });
事件模型和Promise
这样代码的编写阅读都非常困难.好在现在有许多编程模型可以解决这个问题,例如事件模型(发布订阅).
//注册事件监听器 server.on('connection', function (stream) { console.log('someone connected!'); }); //当如下代码被调用时上面的注册回调将被调用 server.emit('connection')//发布事件
不过这样有一个问题,可以想象如果将上面的深层嵌套用这种方式编写,需要发布四次事件和注册四次监听器.本来一段内聚的代码会变得相当松散,依然没有根本解决读写理解困难的问题.下面介绍Promise模型.大概可以这样理解,每当异步处理执行时,总是返回一个Promise,该Promise保证在处理完成或发成错误时才调用后续的方法.Promise通常有这样的API.
promise.then(success,failure)
success,failure分别表示promise承诺的处理成功或失败时的回调函数.
上面的深层嵌套用该模型重写即可变为如下形式
step1().then(step2).then(step3).then(step3)
这样就容易理解多了.要使用Promise模型,需要想node中引入支持库,我们使用'q'这个模块.可以使用npm install q进行安装.'q'这个模块提供了很多工具方法来将普通的回调转换为Promise.使用'q'改写最上面的请求处理,伪代码如下:
var http = require('http'); var queryString = require('queryString'); var url = require('url'); var fs = require('fs'); var q = require('q'); var db = {};//初始化数据库 http.createServer(function (req, resp) { //解析请求参数 var params = queryString.parse(url.parse(req.url).query); //q.all将数组中的promise合并 q.all([ //q.ninvoke将原本的回调式调用转化为返回Promise对象 q.ninvoke(db, 'query', params), q.ninvoke(fs, 'readFile', params.path) ]) //当上述两个promise都处理完成时继续调用 .then(function (result) { //返回结果为一个数组,数组中分别存放上面被组合的promise的结果 var model = result[0]; var template = result[1]; var view = template.replace(/_/, model); resp.end(view); }); }).listen(8124); console.log('server startup');
这样看起来就容易理解多了,但问题是内部细节很难懂.好在有'q'这样的库帮帮我们处理.
使用CoffeeScript让代码变得更紧凑
javascript是一门古老的语言,不免语法冗余了点儿,好在现在有coffeescript这类的简单语言可以编译为javascript来运行.使用coffee来改写上面代码,就更加紧凑了.
http.createServer (req, resp)-> param = queryString.parse(url.parse(req.url).query) q.all([ q.ninvoke(db, 'query', params), q.ninvoke(fs, 'readFile', params.path)]) .then((result)-> model = result[0] template = result[1] view = template.replace(/_/, modle) resp.end view) console.log 'server startup'
参考文献
相关推荐
Node.js异步编程是JavaScript在服务器端运行的一种技术,它基于Chrome V8引擎,以其事件驱动、非阻塞I/O模型而闻名,极大地提高了网络应用的效率和可扩展性。Node.js的核心特性之一就是它的异步处理能力,这使得...
本专题《深入浅出js(Node.js)异步流程控制》将探讨Node.js中的异步编程这一核心概念,帮助开发者更深入地理解和掌握这一技术。 异步编程是Node.js的核心特性之一,它允许程序在等待I/O操作完成时继续执行其他任务...
《Professional Node.js 高级编程》是一本由Pedro Teixeira编著的专业技术书籍,主要探讨了Node.js这一强大的JavaScript后端开发平台。这本书详细介绍了如何利用Node.js进行高效、高性能的应用程序开发,旨在帮助...
* 学习曲线陡峭: Node.js 的异步机制和事件驱动机制需要开发者具备一定的编程基础和经验。 * 不适合计算密集型应用程序: Node.js 不适合计算密集型应用程序,因为它的单线程模型限制了其计算性能。 Node.js 是一...
但不管怎样,异步编程确实是 NodeJS 最大的特点,没有掌握异步编程就不能说是真正学会了 NodeJS。本章将介绍与异步编程相关的各种知识。 在代码中,异步编程的直接体现就是回调。异步编程依托于回调来实现,但不能说...
Node.js的核心特性包括单线程事件循环、异步编程、模块系统以及强大的文件系统操作等。在本书中,你将学习如何利用这些特性来开发高效的应用程序。 1. **事件驱动编程**:Node.js采用事件驱动模型,当有I/O操作时,...
1. **异步编程**:Node.js的核心之一就是异步编程模型,这使得它能够处理大量并发请求,避免了阻塞I/O操作导致的性能瓶颈。书中会深入讲解回调函数、Promise、async/await等异步控制流技术。 2. **事件循环(Event ...
Node.js 是一个开源、跨平台的JavaScript运行环境,它允许开发者在服务器端执行JavaScript代码,极大地拓宽了JavaScript的应用领域。10.16.3-x64 版本是 Node.js 的一个稳定版本,适用于64位操作系统。下面将详细...
2. **异步编程**:Node.js的核心特性之一是其对异步编程的支持。通过回调函数、Promise和async/await等机制,开发者可以处理大量并发请求,避免了传统的多线程模型中的上下文切换开销。 3. **事件循环**:Node.js...
Node.js是一种基于Chrome V8引擎的JavaScript运行环境,它允许开发者在服务器端使用JavaScript进行编程。这个"Node.js最新手册"很可能包含了关于Node.js的最新API、模块系统、事件驱动模型以及异步I/O等内容。 在...
6. **性能优化**:探讨Node.js的性能监控、调试技巧以及优化策略,如异步编程、内存管理等。 7. **部署与维护**:讲解如何将Node.js应用部署到云平台,如Heroku、Docker,以及持续集成和持续部署(CI/CD)的实践。 8...
Node.js 采用了与通常 Web 上的 JavaScript 异步编程的方式来处理会造成阻塞的I/O操作。在 Node.js 中读取文件、访问数据库、网络请求等等都有可能是异步的。对于 Node.js 新人或者从其他语言背景迁移到 Node.js 上...
6. **异步编程**: - **回调函数**:Node.js中的异步操作通常通过回调函数实现,但过度使用可能导致回调地狱问题。 - **Promise**:Promise是解决回调地狱的工具,提供了链式调用和错误处理机制。 - **async/...
2. 掌握异步编程和事件驱动模型。 3. 学会使用Express框架搭建Web应用。 4. 熟悉npm的使用,包括安装、发布和管理依赖。 5. 了解如何进行Node.js应用的测试和部署。 6. 应对实时通信需求,如WebSocket的应用。 7. ...
Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它让JavaScript开发者可以在服务器端执行代码,打破了传统的JavaScript只能在浏览器端运行的限制。这本《Node.js开发实战详解》电子书,显然是为了帮助那些...
回调函数是Node.js异步编程模型的核心,通过回调,Node.js能够在不阻塞主线程的情况下执行I/O操作。作者介绍了匿名函数、lambda表达式和闭包的概念,并将其与PHP 5.3和PHP 4中的相似功能进行了比较。 HTTP响应的...
7. **Promise和async/await**:Node.js从版本7开始引入Promise,从版本8开始支持async/await,为异步编程提供了更优雅的解决方案,降低了回调地狱带来的复杂性。 8. **NPM(Node Package Manager)**:Node.js的包...