1. JavaScript子集和子集的安全性
大多数语言都会定义它们的子集,用以更安全地执行不可信的第三方代码。子集的定义大部分都是出于安全考虑,只有使用这门语言的一个安全的子集编写脚本,才能让代码执行得更安全、更稳定,比如如何更安全地执行一段由不可信第三方提供的广告代码。
子集的设计目的是能在一个容器或“沙箱”中更安全地运行不可信的第三方JavaScript代码。所有能破坏这个沙箱并影响全局执行环境的语言特性和API在这个安全子集中都是禁止的。
2. Node
- Node是基于C++的高速JavaScript解释器,绑定了用于进程、文件和网络套接字等底层Unix API,还绑定了HTTP客户端和服务器API。
- 除了一些专门命名的同步方法外,Node的绑定都是异步的,且Node程序默认绝不阻塞,这意味着它们通常具备强大的可伸缩能力并能有效地处理高负荷。
- 由于API是异步的,因此Node依赖事件处理程序,其通常使用嵌套函数和闭包来实现
Node是在Google的V8 JavaScript引擎上构建而成。Node 0.4使用的是V8的3.1版本,它实现了除严格模式之外的全部ECMAScript 5。
下载、编译并安装Node后,可以使用如下命令运行Node程序:
node program.js
由于Node的函数和方法都是异步的,因此当它们等待运算完成时并不产生阻塞。非异步方法的返回值无法返回异步运算的结果给你。如果想获取异步运算的结果,当异步结果准备好时,就必须提供Node能调用的一个函数进行回调
2.1 Node fs模块
Node的设计目标是高性能I/O,因此其流API常被用到。
"fs"模块包括大量的方法,用于列出文件目录、查询文件属性等。下面的Node程序使用同步的方法列出一个目录的内容,并显示文件大小和修改日期:
var fs = require("fs"),
path = require("path"); //加载需要的模块
var dir = process.cwd(); //当前目录
if (process.argv.length > 2) dir = process.argv[2]; //或来自命令行
var files = fs.readdirSync(dir); //读取目录内容
process.stdout.write("Name\tSize\tDate\n"); //输出头
files.forEach(function(filename) {
//获取每个文件名
var fullname = path.join(dir, filename); //拼接目录和文件名
var stats = fs.statSync(fullname); //获取文件属性
if (stats.isDirectory()) filename += "/"; //标记子目录
process.stdout.write(
filename +
"\t" + //输出文件名+
stats.size +
"\t" + //文件大小+
stats.mtime +
"\n"
); //修改时间
});
2.2 Node示例 HTTP服务器
//这是一个简单的Node HTTP服务器,能处理当前目录的文件,
//并能实现两种特殊的URL用于测试
//用http://localhost:8000或http://127.0.0.1:8000连接这个服务器
//首先,加载所有要用的模块
var http = require("http"); //HTTP服务器API
var fs = require("fs"); //用于处理本地文件
var server = new http.Server(); //创建新的HTTP服务器
server.listen(8000); //在端口8000上运行它
//Node使用"on()"方法注册事件处理程序,
//当服务器得到新请求,则运行函数处理它
server.on("request", function(request, response) {
//解析请求的URL
var url = require("url").parse(request.url); //特殊URL会让服务器在发送响应前先等待
//此处用于模拟缓慢的网络连接
if (url.pathname === "/test/delay") {
//使用查询字符串来获取延迟时长,或者2000毫秒
var delay = parseInt(url.query) || 2000; //设置响应状态码和头
response.writeHead(200, { "Content-Type": "text/plain;charset=UTF-8" }); //立即开始编写响应主体
response.write("Sleeping for " + delay + " milliseconds..."); //在之后调用的另一个函数中完成响应
setTimeout(function() {
response.write("done.");
response.end();
}, delay);
}
//若请求是"/test/mirror",则原文返回它
//当需要看到这个请求头和主体时,会很有用
else if (url.pathname === "/test/mirror") {
//响应状态和头
response.writeHead(200, { "Content-Type": "text/plain;charset=UTF-8" });
//用请求的内容开始编写响应主体
response.write(
request.method + "" + request.url + "HTTP/" + request.httpVersion + "\r\n"
); //所有的请求头
for (var h in request.headers) {
response.write(h + ":" + request.headers[h] + "\r\n");
}
response.write("\r\n"); //使用额外的空白行来结束头
//在这些事件处理程序函数中完成响应:
//当请求主体的数据块完成时,把其写入响应中
request.on("data", function(chunk) {
response.write(chunk);
}); //当请求结束时,响应也完成
request.on("end", function(chunk) {
response.end();
});
}
//否则,处理来自本地目录的文件
else {
//获取本地文件名,基于其扩展名推测内容类型
var filename = url.pathname.substring(1); //去掉前导"/"
var type;
switch (
filename.substring(filename.lastIndexOf(".") + 1) //扩展名
) {
case "html":
case "htm":
type = "text/html;charset=UTF-8";
break;
case "js":
type = "application/javascript;charset=UTF-8";
break;
case "css":
type = "text/css;charset=UTF-8";
break;
case "txt":
type = "text/plain;charset=UTF-8";
break;
case "manifest":
type = "text/cache-manifest;charset=UTF-8";
break;
default:
type = "application/octet-stream";
break;
}
//异步读取文件,并将内容作为单独的数据块传给回调函数
//对于确实很大的文件,使用流API fs.createReadStream()更好
fs.readFile(filename, function(err, content) {
if (err) {
//如果由于某些原因无法读取该文件
response.writeHead(404, {
//发送404未找到状态码
"Content-Type": "text/plain;charset=UTF-8"
});
response.write(err.message); //简单的错误消息主体
response.end(); //完成
} else {
//否则,若读取文件成功
response.writeHead(
200, //设置状态码和MIME类型
{ "Content-Type": type }
);
response.write(content); //把文件内容作为响应主体发送
response.end(); //完成
}
});
}
});
1.模拟缓慢的网络连接
2. 若请求是"/test/mirror",则返回http请求头和主体
3.读取文件内容(注意目录中不能出现中文)