node.js 一个简单的页面输出实现代码


Posted in Javascript onMarch 07, 2012

安装过程就不说了。如果成功是能使用node的命令。node.js调试是非常方便的。每种后台语言都有一个向那个黑黢黢的控制台团输出语用的命令。node.js沿用FF那套东西,也就是console对象与其方法。我们首先建一个example.js文件,内容如下,然后在控制台打开它。

console.log("hello node.js") 
for(var i in console){ 
console.log(i+" "+console[i]) 
} 
node example.js。

你千万不要在node.js使用alert进行调试,那是浏览器带的全局方法,不报错才怪。
输出结果如下:
var log = function () { 
process.stdout.write(format.apply(this, arguments) + '\n'); 
} 
var info = function () { 
process.stdout.write(format.apply(this, arguments) + '\n'); 
} 
var warn = function () { 
writeError(format.apply(this, arguments) + '\n'); 
} 
var error = function () { 
writeError(format.apply(this, arguments) + '\n'); 
} 
var dir = function (object) { 
var util = require('util'); 
process.stdout.write(util.inspect(object) + '\n'); 
} 
var time = function (label) { 
times[label] = Date.now(); 
} 
var timeEnd = function (label) { 
var duration = Date.now() - times[label]; 
exports.log('undefined: NaNms', label, duration); 
} 
var trace = function (label) { 
// TODO probably can to do this better with V8's debug object once that is 
// exposed. 
var err = new Error; 
err.name = 'Trace'; 
err.message = label || ''; 
Error.captureStackTrace(err, arguments.callee); 
console.error(err.stack); 
} 
var assert = function (expression) { 
if (!expression) { 
var arr = Array.prototype.slice.call(arguments, 1); 
require('assert').ok(false, format.apply(this, arr)); 
} 
}

通过这些函数,我们大概了解到node.js在全局作用域添加了些什么,如require, process。但也不能武断说是,因为它们可能是某个作用域的私有对象。不过,了解这些全局对象,并从这些对象上出发去了解其他对象,非常有助于我们了解node.js的生态结构。在前端,每当浏览器升级,我就遍历一下window对象以及其个元素节点就得知它又增加了什么方法与属性,然后再查文档。那些更新日志不可能把全部细节都告诉你的,必须自己动手遍历一下,这样你就比别人知道得更多。好了,我们去找node.js的全局对象。
node.js的文档告诉我们,有如下几个全局对象:
global, process, require,__filename,__dirname, module
但我们为什么能直接使用console.log呢?经验告诉我们,console肯定是某全局对象的成员,正如我们可以alert, 也可以window.alert。好了,我们选遍历一下global这个名字取得非常霸气的对象
for(var i in global){ 
console.log("var " + i+" = "+global[i]) 
}

结果如下:
var global = [object global] 
var process = [object EventEmitter] 
var GLOBAL = [object global] 
var root = [object global] 
var Buffer = function Buffer(subject, encoding, offset) { 
//太长了,省略 
} 
var setTimeout = function () { 
var t = NativeModule.require('timers'); 
return t.setTimeout.apply(this, arguments); 
} 
var setInterval = function () { 
var t = NativeModule.require('timers'); 
return t.setInterval.apply(this, arguments); 
} 
var clearTimeout = function () { 
var t = NativeModule.require('timers'); 
return t.clearTimeout.apply(this, arguments); 
} 
var clearInterval = function () { 
var t = NativeModule.require('timers'); 
return t.clearInterval.apply(this, arguments); 
} 
var console = [object Object]

发现global与浏览器的window一样,都有个指向自身的同名成员。window === window.window, global === global.global。但node.js早期设计得不好,又一搞了个多余的GLOBAL成员。
console.log(global === global.global)//true
console.log(global === global.GLOBAL)//true
我们再遍历module对象:
for(var i in module){ 
console.log("var " + i + " = "+module[i]) 
}

结果如下:
var id = . 
var exports = [object Object] 
var parent = null 
var filename = /home/cheng19840218/node/example.js 
var loaded = false 
var exited = false 
var children = 
var paths = /home/cheng19840218/node/node_modules,/home/cheng19840218/node_modules,/home/node_modules,/node_modules 
var load = function (filename) { 
//太长了,省略 
} 
var _compile = function (content, filename) { 
//太长了,省略 
}

原来那个著名的exports是在此提供的,__filename大概也是filename的引用。只要遍历一下,你就发现许多有趣的东西。但别以为一下秘密就暴光在你眼皮下,还有许多不可遍历属性。比如上面我遍历global对象,只有???墒?父龀稍保?颐强梢允褂?cma262v5新增的方法去考察一下:
console.log(Object.getOwnPropertyNames(global))
结果如下:
[ 'clearInterval', 
'TypeError', 
'decodeURI', 
'Buffer', 
'parseFloat', 
'Number', 
'URIError', 
'encodeURIComponent', 
'RangeError', 
'ReferenceError', 
'RegExp', 
'Array', 
'isNaN', 
'setTimeout', 
'console', 
'Date', 
'Infinity', 
'Boolean', 
'Error', 
'root', 
'NaN', 
'String', 
'Function', 
'Math', 
'undefined', 
'encodeURI', 
'escape', 
'unescape', 
'process', 
'decodeURIComponent', 
'EvalError', 
'clearTimeout', 
'GLOBAL', 
'setInterval', 
'SyntaxError', 
'Object', 
'eval', 
'global', 
'parseInt', 
'JSON', 
'isFinite' ]

许多人学node.js就立即看其文档,殊不知node.js本身所依赖的V8引擎就拥有许多要学的东西,这其中包括ecma262v5带来的新方法新对象,还有效仿firefox的一些语法:
__defineGetter__
__defineSetter__
__lookupGetter__
__lookupSetter__
set
get
__proto__
不过以"__"开头的东西我是不建议用的,像set与get现在最新的浏览器都支持,如IE9,可以在其开发人员工具下试试下面的脚本:
var a = { 
get latest () { 
if (this.log.length > 0) { 
return this.log[this.log.length - 1]; 
} 
else { 
return null; 
} 
}, 
log: [] 
} 
a.log[0] = "a"; 
a.log[1] = "b"; 
console.log(a.latest)

在node.js基本上没有兼容问题(如果你不是从早期的node.js玩起来),而且原生对象又加了这么多扩展,再加上node.js自带的库,每个模块都提供了花样繁多的API,如果还嫌不够,github上还有上千个插件。对于想向尝试一下后端编程的JSer来说,这是极具诱惑力的。可能有人说,后端不是涉及数据库操作吗?这与比前端的DOM兼容比起来,不值一提。还有什么文件夹与文件操作 ,你就当成是一种特殊的数组操作就是。因此你完全可以愤愤不平!
好了,我们来点实质的内容吧。node.js本来就是一个http服务器,它是要与前端交互的,因此少不了两个对象:请求(request)与响应(response)。请求与响应显然一种异步的东西,因为我们 不知道前端什么时候发请求过来,响应也不能立即给前端,还要做日志,读写数据库等操作呢。因此对于javascript来说,这用回调函数来实现最好。那么由?来接受这个回调呢?一个服务器对象!
var http = require("http"); 
http.createServer(function(request, response) { 
response.writeHead(200, {"Content-Type": "text/plain"}); 
response.write("Hello node.js"); 
response.end(); 
}).listen(8888);

node.js有个特殊的require,用于同步加载其他模块的对象,这与其他语言的require, import差不多。能同步就是好,不像前端那样一层套一层。然后利用一个函数去实例化一个服务器对象,然后监听8888端口。这是node.js官网最初的例子,大家都写烂了。但这样的程序在现实中一无是处,我们在地址栏上输入URL,你起码要返回一个完整页面给我吧!
对此,我们首先要进行模块化。模块化是以文件为单位的,把example.js更名为server.js,然后再把里面的内容改为一个模块。对于一个node.js的文件,其实它里面的内容是在一个封闭的环境中执行。要想共享给其他模块使用,就必须绑定在exports对象上。
var http = require("http"); 
exports.start = function(){ 
http.createServer(function(request, response) { 
console.log("Request received..."); 
response.writeHead(200, {"Content-Type": "text/plain"}); 
response.write("Hello node.js"); 
response.end(); 
}).listen(8888); 
console.log("server start..."); 
}

然后我们再建一个index.js作为入口(index.js与server.js放在同一目录下)。
var server = require("./server"); 
server.start();

然后建一个index.html页面。
<!doctype html> 
<html> 
<head> 
<title>index</title> 
<meta content="IE=8" http-equiv="X-UA-Compatible"/> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> 
<body> 
<h2>这是首页</h2> 
</body> 
</html>

现在我们就在要请求过来时,把此页的内容读出来,返给用户。这时我们就要用到fs模块的方法了。
var http = require("http"); 
var fs = require('fs'); 
exports.start = function(){ 
http.createServer(function(request, response) { 
fs.readFile('./index.html', 'utf-8',function (err, data) {//读取内容 
if (err) throw err; 
response.writeHead(200, {"Content-Type": "text/html"});//注意这里 
response.write(data); 
response.end(); 
}); 
}).listen(8888); 
console.log("server start..."); 
}

好了,这时我们重启再次输入地址,就看到一个完整的页面了。
但一个页面除了HTML结构层外,还有javascript与css。那么,我们在当前目录建一个文件夹javascripts, 里面建index.js,内容如下:
window.onload = function(){ 
var p = document.createElement("p"); 
p.innerHTML = "这是动态添加的" 
document.body.appendChild(p); 
}

再建一个styles目录,里面建index.css,内容如下:
html,body{ 
background: #3671A5; 
height: 100% 
}

然后在index.html引入这两个文件:
<!doctype html> 
<html> 
<head> 
<title>index</title> 
<meta content="IE=8" http-equiv="X-UA-Compatible"/> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<link type="text/css" rel="stylesheet" href="styles/index.css"/> 
<script src="/javascripts/index.js"></script> 
</head> 
<body> 
<h2>这是首页</h2> 
</body> 
</html>

重新打开,发现没有改变,google,说要处理js与css文件的请求。没有办法,取得request.url属性,再判定后缀名,为它进行文件读取与设置首部。
var http = require("http"); 
var fs = require('fs'); 
var url = require('url'); 
exports.start = function(){ 
http.createServer(function(request, response) { 
var pathname = url.parse(request.url).pathname; 
var ext = pathname.match(/(\.[^.]+|)$/)[0];//取得后缀名 
switch(ext){ 
case ".css": 
case ".js": 
fs.readFile("."+request.url, 'utf-8',function (err, data) {//读取内容 
if (err) throw err; 
response.writeHead(200, { 
"Content-Type": { 
".css":"text/css", 
".js":"application/javascript", 
}[ext] 
}); 
response.write(data); 
response.end(); 
}); 
break; 
default: 
fs.readFile('./index.html', 'utf-8',function (err, data) {//读取内容 
if (err) throw err; 
response.writeHead(200, { 
"Content-Type": "text/html" 
}); 
response.write(data); 
response.end(); 
}); 
} 
}).listen(8888); 
console.log("server start..."); 
}

node.js 一个简单的页面输出实现代码 
至此,本文的目的达到了。三个node.js文件,一个普通的js文件,一个css文件,一个html文件。下一个目的就是多页了,一个网站是由多个目的构成的。它包含如下内容,能处理ajax请求,上传文件,Session与Cookie支持,日志,MIME识别,路由派发,缓存系统......要做的事多得吓人,因此有人一上来就框架,与学JS那样,连API还没有摸熟就用jQuery了,那学个毛!回顾一下我们上面的server.js中间的部分,其实就要把MIME与路由拆分出来的。但最重要的事还有一样,如何处理这无穷的函数嵌套?本人觉得这与我的模块加载系统还没有什么两样,下次就从这里动手吧。
Javascript 相关文章推荐
JS request函数 用来获取url参数
May 17 Javascript
基于jquery的高性能td和input切换并可修改内容实现代码
Jan 09 Javascript
AngularJS使用ocLazyLoad实现js延迟加载
Jul 05 Javascript
深入理解vue2.0路由如何配置问题
Jul 18 Javascript
JS鼠标3次点击事件实现代码及扩展思路
Sep 12 Javascript
ionic3+Angular4实现接口请求及本地json文件读取示例
Oct 11 Javascript
three.js中文文档学习之通过模块导入
Nov 20 Javascript
浅谈react受控组件与非受控组件(小结)
Feb 09 Javascript
基于vue-simplemde实现图片拖拽、粘贴功能
Apr 12 Javascript
微信小程序实现星级评价效果
Dec 28 Javascript
JS实现贪吃蛇游戏
Nov 15 Javascript
vuex入门最详细整理
Mar 04 Javascript
服务器端的JavaScript脚本 Node.js 使用入门
Mar 07 #Javascript
JavaScript高级程序设计 读书笔记之十一 内置对象Global
Mar 07 #Javascript
拥抱模块化的JavaScript
Mar 07 #Javascript
那些年,我还在学习jquery 学习笔记
Mar 05 #Javascript
什么是DOM(Document Object Model)文档对象模型
Mar 05 #Javascript
JQuery魔力之$(&quot;tagName&quot;)与selector
Mar 05 #Javascript
30个让人兴奋的视差滚动(Parallax Scrolling)效果网站
Mar 04 #Javascript
You might like
DC宇宙的第一个英雄,堪称动漫史鼻祖,如今成为美国文化的象征
2020/04/09 欧美动漫
php面向对象全攻略 (九)访问类型
2009/09/30 PHP
php实现的AES加密类定义与用法示例
2018/01/29 PHP
使用JavaScript switch case 另类写法
2010/03/14 Javascript
js处理json以及字符串的比较等常用操作
2013/09/08 Javascript
用js来获取上传的文件名纯粹是为了美化而用
2013/10/23 Javascript
鼠标选择动态改变网页背景颜色的JS代码
2013/12/10 Javascript
jquery中one()方法的用法实例
2015/01/16 Javascript
理解javascript中DOM事件
2015/12/25 Javascript
jquery组件WebUploader文件上传用法详解
2020/10/23 Javascript
原生js编写基于面向对象的分页组件
2016/12/05 Javascript
Vue.js自定义事件的表单输入组件方法
2018/03/08 Javascript
js调用设备摄像头的方法
2018/07/19 Javascript
详解如何创建并发布一个 vue 组件
2018/11/08 Javascript
JS实现点击生成UUID的方法完整实例【基于jQuery】
2019/06/12 jQuery
[04:00]DOTA2解说界神雕侠侣 CJ第四天谷子现场过生日
2013/07/30 DOTA
Python中对列表排序实例
2015/01/04 Python
30分钟搭建Python的Flask框架并在上面编写第一个应用
2015/03/30 Python
Python的Django框架下管理站点的基本方法
2015/07/17 Python
Python编程之基于概率论的分类方法:朴素贝叶斯
2017/11/11 Python
用python 批量更改图像尺寸到统一大小的方法
2018/03/31 Python
python 划分数据集为训练集和测试集的方法
2018/12/11 Python
python如何实现代码检查
2019/06/28 Python
Python使用Chrome插件实现爬虫过程图解
2020/06/09 Python
详解Python+Selenium+ChromeDriver的配置和问题解决
2021/01/19 Python
CSS去掉A标签(链接)虚线框的方法
2014/04/01 HTML / CSS
巴西食品补充剂在线零售商:Músculos na Web
2017/08/07 全球购物
Banana Republic英国官网:香蕉共和国,GAP集团旗下偏贵族风
2018/04/24 全球购物
局域网定义和特性
2016/01/23 面试题
荷叶母亲教学反思
2014/04/30 职场文书
体育节口号
2014/06/19 职场文书
单位工作证明
2014/10/07 职场文书
毕业实习证明(4篇)
2014/10/28 职场文书
百善孝为先:关于孝道的经典语录
2019/10/18 职场文书
python树莓派通过队列实现进程交互的程序分析
2021/07/04 Python
Redisson实现Redis分布式锁的几种方式
2021/08/07 Redis