nodejs和vue的那些事【分分快三计划】

作者:分分快三计划

1. RESTful API

 return $require.cache[filename].exports;

C:> npmUsage: npm where is one of: ...

缺点:

streamReader.on('data',function(chunk){  data =chunk.tostring(); });

600

模块的加载机制

CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。请看下面这个例子。

下面是一个模块文件lib.js

// lib.js
var counter = 3;
function incCounter() {
  counter  ;
}
module.exports = {
  counter: counter,
  incCounter: incCounter,
};

上面代码输出内部变量counter和改写这个变量的内部方法incCounter

然后,加载上面的模块。

// main.js
var counter = require('./lib').counter;
var incCounter = require('./lib').incCounter;

console.log(counter);  // 3
incCounter();
console.log(counter); // 3

上面代码说明,counter输出以后,lib.js模块内部的变化就影响不到counter了。

写一个歌词滚动效果的实现:

安装Node.js

官方网站:

next();

由于Node.js平台是在后端运行JavaScript代码,所以,必须首先在本机安装Node环境。

模块的循环加载

如果发生模块的循环加载,即A加载B,B又加载A,则B将加载A的不完整版本。

// a.js
exports.x = 'a1';
console.log('a.js ', require('./b.js').x);
exports.x = 'a2';

// b.js
exports.x = 'b1';
console.log('b.js ', require('./a.js').x);
exports.x = 'b2';

// main.js
console.log('main.js ', require('./a.js').x);
console.log('main.js ', require('./b.js').x);

上面代码是三个JavaScript文件。其中,a.js加载了b.js,而b.js又加载a.js。这时,Node返回a.js的不完整版本,所以执行结果如下。

$ node main.js
b.js  a1
a.js  b2
main.js  a2
main.js  b2

修改main.js,再次加载a.js和b.js。

// main.js
console.log('main.js ', require('./a.js').x);
console.log('main.js ', require('./b.js').x);
console.log('main.js ', require('./a.js').x);
console.log('main.js ', require('./b.js').x);

执行上面代码,结果如下。

$ node main.js
b.js  a1
a.js  b2
main.js  a2
main.js  b2
main.js  a2
main.js  b2

上面代码中,第二次加载a.js和b.js时,会直接从缓存读取exports属性,所以a.js和b.js内部的console.log语句都不会执行了。

 

安装好文本编辑器后,输入以下代码:

4. 非阻塞I/O

});

fs.createWriteStream('output1.txt','utf-8');ws1.write('使用Stream写入文本数据...n');ws1.write('END.');ws1.end();varws2

fs.createWriteStream('output2.txt');ws2.write(newBuffer('使用Stream写入二进制数据...n','utf-8'));ws2.write(newBuffer('END.','utf-8'));ws2.end();

所有可以读取数据的流都继承自stream.Readable,所有可以写入的流都继承自stream.Writable。

pipe

就像可以把两个水管串成一个更长的水管一样,两个流也可以串起来。一个Readable流和一个Writable流串起来后,所有的数据自动从Readable

流进入Writable流,这种操作叫pipe。

在Node.js中,Readable流有一个pipe()方法,就是用来干这件事的。

让我们用pipe()把一个文件流和另一个文件流串起来,这样源文件的所有数据就自动写入到目标文件里了,所以,这实际上是一个复制文件的程序:

'use strict';varfs =require('fs');varrs = fs.createReadStream('sample.txt');varws = fs.createWriteStream('copied.txt');rs.pipe(ws);

默认情况下,当Readable流的数据读取完毕,end事件触发后,将自动关闭Writable流。如果我们不希望自动关闭Writable流,需要传入参数:

readable.pipe(writable, {end:false});

http

Node.js开发的目的就是为了用JavaScript编写Web服务器程序。因为JavaScript实际上已经统治了浏览器端的脚本,其优势就是有世界上数量最多的前端开发人员。如果已经掌握了JavaScript前端开发,再学习一下如何将JavaScript应用在后端开发,就是名副其实的全栈了。

HTTP协议

要理解Web服务器程序的工作原理,首先,我们要对HTTP协议有基本的了解。如果你对HTTP协议不太熟悉,先看一看HTTP协议简介。

HTTP服务器

要开发HTTP服务器程序,从头处理TCP连接,解析HTTP是不现实的。这些工作实际上已经由Node.js自带的http模块完成了。应用程序并不直接和HTTP协议打交道,而是操作http模块提供的request和response对象。

request对象封装了HTTP请求,我们调用request对象的属性和方法就可以拿到所有HTTP请求的信息;

response对象封装了HTTP响应,我们操作response对象的方法,就可以把HTTP响应返回给浏览器。

用Node.js实现一个HTTP服务器程序非常简单。我们来实现一个最简单的Web程序hello.js,它对于所有请求,都返回Hello world!:

'use strict';// 导入http模块:varhttp =require('http');// 创建http server,并传入回调函数:varserver = http.createServer(function(request, response){// 回调函数接收request和response对象,// 获得HTTP请求的method和url:console.log(request.method ': ' request.url);// 将HTTP响应200写入response, 同时设置Content-Type: text/html:response.writeHead(200, {'Content-Type':'text/html'});// 将HTTP响应的HTML内容写入response:response.end('

例如个性化应用,每个用户看到的页面都不一样,缓存失效,需要在页面加载的时候发起Ajax请求,NodeJS能响应大量的并发请求。  总而言之,NodeJS适合运用在高并发、I/O密集、少量业务逻辑的场景。

var rl = readline.createInterface({ input:streamReader });

直接运行node hello.js文件相当于启动了Node解释器,然后一次性把hello.js文件的源代码给执行了,你是没有机会以交互的方式输入源代码的。

require.main

require方法有一个main属性,可以用来判断模块是直接执行,还是被调用执行。

直接执行的时候(node module.js),require.main属性指向模块本身。

require.main === module
// true

调用执行的时候(通过require加载该脚本执行),上面的表达式返回false。

let code = fs.readFileSync(filename,'utf8');

众所周知,在Netscape设计出JavaScript后的短短几个月,JavaScript事实上已经是前端开发的唯一标准。

3. 事件驱动

 

在Windows上安装时务必选择全部组件,包括勾选Add to Path。

Ryan dahl对node.js初衷

2008年,我在寻找一个新的编程平台来做网站。我并不是想要一门新的语言,实际上,语言自身的细节对我来说并不重要。我真正关心的是,该语言能否提供先进的推送功能并集成到网站中来,就像我在Gmail中看到的那样——能够从服务器端把数据主动推送给用户,而不是采用不断轮询拉取数据的方式。现有的平台都把服务器作为接受请求然后返回相应内容的设备。要把事件推送到浏览器,平台需要能够持续处理大量打开的网络连接,而这其中有许多连接其实是空闲的。

我知道如何使用系统调用(用C)实现这样的功能。如果只使用非阻塞式socket,每个连接的开销都会非常小。在小规模测试中,我可以演示一台服务器,它能同时处理几千个闲置连接,或实现相当大的吞吐量。我知道这是在Unix服务器上用户空间程序能够实现的最优操作了。但是,我并不想使用C,我需要的是一种漂亮灵活的动态语言。如果需要,我可以在每种编程语言中都用一模一样的系统调用,但这样做异常丑陋,而且这只是socket编程的“替代”方法而已。我认为,非阻塞socket编程并非那么困难,只要一切都做成非阻塞的就可以实现了。

于是,我有了个主意:JavaScript结合非阻塞socket!因为JavaScript并没有现成的socket库,所以我可以勇做第一人,来推介这个崭新且大有前途的接口。只要把V8接上我的非阻塞C代码,我就能把它完成。我终止了当时承接的工作,开始全力实现这个想法。当我编写好并发布了最初的版本后,立刻就有用户开始反馈bug,然后我开始不停地处理这些bug,就这样,不知不觉过去了3年。

实践证明,JavaScript与非阻塞socket配合得相当完美。开始我并不敢肯定这一点,但闭包让所有事情变得可能。只需要简单的几行JavaScript代码,就可以构建出非常复杂的非阻塞服务器。我最初还担心,系统会过于小众,但很快我就放心了,因为世界各地的黑客们纷纷开始为其编写程序库。唯一的事件循环队列和纯粹的非阻塞接口让程序库不必增加昂贵的线程,就能添加越来越多的复杂功能。

在Node中,用户会发现系统在默认情况下就能很好地扩展。因为其核心系统做出的选择是,不允许系统中的任何部分做出太坏的事情来(比如堵塞当前线程),所以整体性能也不会太差。如果以能够处理的流量作为计量,Node的方法要比传统的阻塞式操作好上一个数量级。

现在,Node已经在全球被众多公司所使用,包括创业公司、Voxer、Uber,以及沃尔玛、微软这样的知名公司。可以说,每天通过Node处理的请求数以亿计。随着越来越多的人参与到本项目中来,可用的第三方模块和扩展增长迅猛,而且质量也不断提升。虽然我曾建议将Node用于关键任务应用,但现在,即便是要求最苛刻的服务器系统,我也会热诚地推荐使用Node。

>5.commonjs

1.如何定义一个自定义的模块

一个文件就是一个模块 a.js 文件名就是模块 a

2.模块中能放那些东西

* function class variable*

Node,CommonJS,浏览器甚至是W3C之间有什么关系:

  |---------------浏览器----- ------------------|        |--------------------------CommonJS----------------------------------|

 

  |  BOM  |       | DOM |        | ECMAScript |         | FS |           | TCP |         | Stream |        | Buffer |          |........|

 

  |-------W3C-----------|       |---------------------------------------Node--------------------------------------------------|

CommonJS定义的模块分为:{模块引用(require)} {模块定义(exports)} {模块标识(module)}

 

require()用来引入外部模块;exports对象用于导出当前模块的方法或变量,唯一的导出口;module对象就代表模块本身。

 //sum.js

 exports.sum = function(){...做加操作..};

 

 //calculate.js

 var math = require('sum');

exports.add = function(n){

    return math.sum(val,n);

 };

 

CommonJS定义的模块分为:{模块引用(require)} {模块定义(exports)} {模块标识(module)}

 

require()用来引入外部模块;exports对象用于导出当前模块的方法或变量,唯一的导出口;module对象就代表模块本身。

 //sum.js

 exports.sum = function(){...做加操作..};

 

 //calculate.js

 var math = require('sum');

exports.add = function(n){

    return math.sum(val,n);

 };

 

二、AMD

 

CommonJS是主要为了JS在后端的表现制定的,他是不适合前端的,为什么这么说呢?

 

这需要分析一下浏览器端的js和服务器端js都主要做了哪些事,有什么不同了:

 

 

 

---------------------------------------服务器端JS   |    浏览器端JS-------------------------------------------

 

                                   相同的代码需要多次执行  |    代码需要从一个服务器端分发到多个客户端执行

 

                                     CPU和内存资源是瓶颈   |    带宽是瓶颈

 

                                        加载时从磁盘中加载   |    加载时需要通过网络加载

 


 

 

 

于是乎,AMD(异步模块定义)出现了,它就主要为前端JS的表现制定规范。

 

AMD就只有一个接口:define(id?,dependencies?,factory);

 

它要在声明模块的时候制定所有的依赖(dep),并且还要当做形参传到factory中,像这样:

 

 

 

 define(['dep1','dep2'],function(dep1,dep2){...});

 

 

define(function(){

     var exports = {};

     exports.method = function(){...};

     return exports;

 });

 

 

在命令行模式下,可以执行node进入Node交互式环境,也可以执行nodehello.js运行一个.js文件。看到>是在Node交互式环境下:

require的内部处理流程

require命令是CommonJS规范之中,用来加载其他模块的命令。它其实不是一个全局命令,而是指向当前模块的module.require命令,而后者又调用Node的内部命令Module._load

Module._load = function(request, parent, isMain) {
  // 1. 检查 Module._cache,是否缓存之中有指定模块
  // 2. 如果缓存之中没有,就创建一个新的Module实例
  // 3. 将它保存到缓存
  // 4. 使用 module.load() 加载指定的模块文件,
  //    读取文件内容之后,使用 module.compile() 执行文件代码
  // 5. 如果加载/解析过程报错,就从缓存删除该模块
  // 6. 返回该模块的 module.exports
};

上面的第4步,采用module.compile()执行指定模块的脚本,逻辑如下。

Module.prototype._compile = function(content, filename) {
  // 1. 生成一个require函数,指向module.require
  // 2. 加载其他辅助方法到require
  // 3. 将文件内容放到一个函数之中,该函数可调用 require
  // 4. 执行该函数
};

上面的第1步和第2步,require函数及其辅助方法主要如下。

  • require(): 加载外部模块
  • require.resolve():将模块名解析到一个绝对路径
  • require.main:指向主模块
  • require.cache:指向所有缓存的模块
  • require.extensions:根据文件的后缀名,调用不同的执行函数

一旦require函数准备完毕,整个所要加载的脚本内容,就被放到一个新的函数之中,这样可以避免污染全局环境。该函数的参数包括requiremoduleexports,以及其他一些参数。

(function (exports, require, module, __filename, __dirname) {
  // YOUR CODE INJECTED HERE!
});

Module._compile方法是同步执行的,所以Module._load要等它执行完成,才会向用户返回module.exports的值。

分分快三计划 1

require方法接受以下几种参数的传递:

  1. http、fs、path等,原生模块。
  2. ./mod或../mod,相对路径的文件模块。
  3. /pathtomodule/mod,绝对路径的文件模块。
  4. mod,非原生模块的文件模块。
    当require一个文件模块时,从当前文件目录开始查找node_modules目录;然后依次进入父目录,查找父目录下的
    node_modules目录;依次迭代,直到根目录下的node_modules目录。
    简而言之,如果require绝对路径的文件,查找时不会去遍历每一个node_modules目录,其速度最快。其余
    流程如下:
    从module path数组中取出第一个目录作为查找基准。
    1. 直接从目录中查找该文件,如果存在,则结束查找。如果不存在,则进行下一条查找。
    2. 尝试添加.js、.json、.node后缀后查找,如果存在文件,则结束查找。如果不存在,则进行下一条。
    3. 尝试将require的参数作为一个包来进行查找,读取目录下的package.json文件,取得main参数指定的文件。
  5. 尝试查找该文件,如果存在,则结束查找。如果不存在,则进行第3条查找
  6. 如果继续失败,则取出module path数组中的下一个目录作为基准查找,循环第1至5个步骤。
  7. 如果继续失败,循环第1至6个步骤,直到module path中的最后一个值。
  8. 如果仍然失败,则抛出异常。
    module.exports还是exports
    一个模块可以通过module.exports或exports将函数、变量等导出,以使其它JavaScript脚本通过require()函数引
    入并使用。
    如果你想你的模块是一个特定的类型就用module.exports。如果你想的模块是一个典型
    的”实例化对象”就用exports。
    require返回的其实是module.exports这个方法,exports其实是指向module.exports的一个引用
    二、Node.js的Path对象
    NodeJS中的Path对象,用于处理目录的对象,提高开发效率。 用NodeJS的Path命令,与使用Linux下的shell脚本
    命令相似。
    引入path对象:
    var path = require('path');
    比较实用的方法:
  9. path.normalize(p) : 格式化路径
    特点:将不符合规范的路径格式化,简化开发人员中处理各种复杂的路径判断
  10. path.join([path1], [path2], […]) : 路径合并
    特点:将所有名称用path.seq串联起来,然后用normailze格式化
  11. path.resolve([from …], to) : 路径寻航
    特点:相当于不断的调用系统的cd命令
    示例:
    path.normalize('/foo/bar//baz/asdf/quux/..');
    => '/foo/bar/baz/asdf'
    示例:
    path.join('///foo', 'bar', '//baz/asdf', 'quux', '..');
    =>'/foo/bar/baz/asdf'
  12. path.relative(from, to) : 相对路径
    特点:返回某个路径下相对于另一个路径的相对位置串,相当于:path.resolve(from, path.relative(from,
    to)) == path.resolve(to)
  13. path.dirname(p) : 文件夹名称
    特点:返回路径的所在的文件夹名称
  14. path.basename(p, [ext]) : 文件名称
  15. path.basename(p, [ext]) : 文件名称
    特点:返回指定的文件名,返回结果可排除[ext]后缀字符串
  16. 扩展名称 path.extname(p)
    示例:
    path.resolve('foo/bar', '/tmp/file/', '..', 'a/../subfile')
    //相当于:
    cd foo/bar
    cd /tmp/file/
    cd ..
    cd a/../subfile
    pwd
    示例:
    path.relative('C:\orandea\test\aaa', 'C:\orandea\impl\bbb')
    =>'..\..\impl\bbb'
    path.relative('/data/orandea/test/aaa', '/data/orandea/impl/bbb')
    =>'../../impl/bbb'
    示例:
    path.dirname('/foo/bar/baz/asdf/quux')
    =>'/foo/bar/baz/asdf'
    示例
    path.basename('/foo/bar/baz/asdf/quux.html')
    =>'quux.html'
    path.basename('/foo/bar/baz/asdf/quux.html', '.html')
    =>'quux'
    特点:返回指定文件名的扩展名称
  17. 特定平台的文件分隔符 path.sep
    特点:获取文件路径的分隔符,主要是与操作系统相关
  18. 特定平台的路径分隔符 path.delimiter
    特定平台的路径分隔符, ‘;‘ 或者 ‘:‘.
    Linux 上的例子:
    Windows 上的例子:
    示例:
    path.extname('index.html')
    =>'.html'
    path.extname('index.')
    =>'.'
    path.extname('index')
    =>''
    示例:
    linux:
    'foo/bar/baz'.split(path.sep)
    =>['foo', 'bar', 'baz']
    window:
    'foo\bar\baz'.split(path.sep)
    =>['foo', 'bar', 'baz']
    process.env.PATH.split(path.delimiter)
    // returns
    ['/usr/bin', '/bin', '/usr/sbin', '/sbin', '/usr/local/bin']
    console.log(process.env.PATH)
    // 'C:Windowssystem32;C:Windows;C:Program Filesnodejs'
    process.env.PATH.split(path.delimiter)
    // returns
    ['C:Windowssystem32', 'C:Windows', 'C:Program Filesnodejs']
    process.env.PATH.split(path.delimiter)
    // returns
    ['C:Windowssystem32', 'C:Windows', 'C:Program Filesnodejs']
    nodejs 全局变量
  19. module.filename:开发期间,该行代码所在的文件。
  20. __filename:始终等于 module.filename。
  21. __dirname:开发期间,该行代码所在的目录。
  22. process.cwd():运行node的工作目录,可以使用 cd /d 修改工作目录。
  23. require.main.filename:用node命令启动的module的filename, 如 node xxx,这里的filename就是这个
    xxx。
    require()方法的坐标路径是:module.filename;
    fs.readFile()的坐标路径是:process.cwd()。

异步(async)和同步(sync)
Nodejs中Api一般都是异步的接口,如果调用同步的只需要在后面加上xxxSync()。
Node.js 文件系统(fs 模块)模块中的方法均有异步和同步版本,例如读取文件内容的函数有异步的
fs.readFile() 和同步的 fs.readFileSync()。
Node文件系统:目录操作

  1. 判断文件路径是否存在: fs.exists(path, callback)
    参数说明:
  2. 创建目录 fs.mkdir/mkdirSync(path[, mode], callback)
    var fs = require("fs");
    //异步读取文件
    fs.readFile('input.txt', function (err, data) {
    if (err) {
    return console.error(err);
    }
    console.log("Asynchronous read: " data.toString());
    });
    // /同步读取文件
    var data = fs.readFileSync('input.txt');
    console.log("Synchronous read: " data.toString());
    console.log("Program Ended");
    path 欲检测的文件路径
    callback 回调
    fs.exists("test",function(exists){
    console.log(exists);
    })
    path - 文件路径 ; mode - 设置目录权限,默认为0777 callback - 回调函数
  3. 查看目录 fs.readdir(path, callback(err, files))
    path - 文件路径。
    callback - 回调函数,回调函数带有两个参数err, files,err 为错误信息,files 为 目录下的文件数组列表
    返回结果: [ 'note.txt' ]
  4. 删除目录 fs.rmdir(path, callback)
    参数使用说明如下:
    path - 文件路径。 callback - 回调函数,没有参数。
    注意:只能删除空的目录,有文件的目录会报错:
    [Error: ENOTEMPTY: directory not empty, rmdir 'F:FullStack-Cource-2017Nodejs-Laravel-Action\03-
    Node模块-FileSystemtest']
    Node文件模块:文件操作说明
  5. 写入文件 fs.writeFile(filename, data[, options], callback)
    如果文件存在,写入的内容会覆盖旧文件内容
    参数使用说明如下:
    var fs = require("fs");
    fs.mkdir("test",function(error){
    if (err) return console.error(err);
    console.log('目录创建成功');
    })
    fs.readdir("test",function(error,files){
    console.log(files);
    })
    fs.rmdir("test",function(error){
    console.log(error);
    })
  6. 文件读取 fs.readFile( url , code , callback);
  7. 异步读取文件
    fs.readFile("test/1.txt","utf-8",function(error,data){ console.log(data); })
  8. 异步读取文件
    var data =fs.readFileSync("test/1.txt","utf-8"); console.log(data);
  9. 向文件中追加写入 fs.appendFile(name,str,encode,callback);
    参数说明:
    name : 文件名 str : 添加的字段 encode : 设置编码 callback : 回调函数
    栗子
    fs.appendFile("test/1.txt",'窗前明月光,疑是地上霜','utf8',function(eror){
    })
  10. 改变文件名 : fs.rename(old文件名,新文件名,callback(传递一个err
    参数))
    fs.rename("test/1.txt","test/a.txt",function(error){
    })
  11. 查看文件状态 fs.stat(fileaddr,callback(error,stats))
    在fs模块中,可以使用 fs.stat() 方法或 fs.lstat() 方法查看一个文件或目录的信息,如文件的大小、创建时
    间、权限等信息。这两个方法的唯一区别是当查看符号链接文件的信息时,必须使用 fs.lstat() 方法。
    var fs = require("fs"); var path = require("path");
    path - 文件路径。
    data - 要写入文件的数据,可以是 String(字符串) 或 Buffer(流) 对象。
    options - 该参数是一个对象,包含 {encoding, mode, flag}。默认编码为 utf8, 模式为 0666 ,flag 为
    'w'
    callback - 回调函数,回调函数只包含错误信息参数(err),在写入失败时返回。
    var fs = require("fs");
    fs.writeFile("test/1.txt","hello file",function(error){
    console.log(error);
    })
    var fileaddr = path.resolve(__dirname,"file/note.txt");
    /**
    * fileaddr: 需要查看状态的相对,或者绝对地址
    fs.Stats对象的方法如下:
    stats.isFile() : 判断被查看对象是否是一个文件。如果是标准文件,返回true。是目录、套接字、符号连
    接、或设备等返回false。
    stats. isDirectory() : 判断被查看对象是否是一个目录。如果是目录,返回true。
    stats. isBlockDevice() : 判断被查看对象是否是一个块设备文件。 如果是块设备,返回true,大多数情况下
    类UNIX系统的块设备都位于/dev目录下。
    stats. isCharacterDevice() : 判断被查看对象是否是一个字符设备文件。如果是字符设备,返回true。
    stats. isSymbolicLink() : 判断被查看对象是否是一个符号链接文件。如果是符号连接,返回true。该方法仅
    在fs.lstat()方法的回调函数中有效。
    stats.isFIFO() : 判断被查看对象是否是一个FIFO文件。如果是FIFO,返回true。FIFO是UNIX中的一种特殊
    类型的命令管道。该方法仅在LINUX系统下有效。
    stats.isSocket() : 判断被查看对象是否是一个socket文件。 如果是UNIX套接字,返回true。该方法仅在
    LINUX系统下有效。
    fs.Stats对象的属性如下:
    dev : 文件或目录所在的设备ID。该属性值在UNIX系统下有效;
    mode : 文件或目录的权限标志,采用数值形式表示;
    nlink : 文件或目录的的硬连接数量;
    uid : 文件或目录的所有者的用户ID。该属性值在UNIX系统下有效;
    gid : 文件或目录的所有者的用户组ID。该属性值在UNIX系统下有效;
    rdev : 字符设备文件或块设备文件所在设备ID。该属性值在UNIX系统下有效;**
    ino : 文件或目录的索引编号。该属性值仅在UNIX系统下有效;
    size : 文件的字节数;
    * callback(error,stats): error:返回的错误信息
    * stats:返回的成功信息
    */
    fs.stat(fileaddr,function(error,stats){
    if(error){
    console.log(error)
    }else{
    console.log(stats);
    console.log(stats.isFile());
    console.log(stats.isDirectory());
    console.log(stats.isCharacterDevice());
    console.log(stats.isSymbolicLink());
    console.log(stats.isFIFO());
    console.log(stats.isSocket());
    console.log(stats.isBlockDevice());
    }
    })
    atime : 文件或目录的访问时间;
    mtime : 文件或目录的最后修改时间;
    ctime : 文件或目录状态的最后修改时间;
    birthtime : 文件创建时间,文件创建时生成。在一些不提供文件
    birthtime 的文件系统中,这个字段会使用 ctime 或 1970-01-01T00:00Z 来填充;
  12. 删除文件 fs.unlink(path, callback)
    参数说明
    path - 文件路径 callback - 回调函数,无参
    fs.unlink("test/a.txt",function(){})

url

┌─────────────────────────────────────────────────────────────────────────────────────────────┐
│                                            href                                             │
├──────────┬──┬─────────────────────┬─────────────────────┬───────────────────────────┬───────┤
│ protocol │  │        auth         │        host         │           path            │ hash  │
│          │  │                     ├──────────────┬──────┼──────────┬────────────────┤       │
│          │  │                     │   hostname   │ port │ pathname │     search     │       │
│          │  │                     │              │      │          ├─┬──────────────┤       │
│          │  │                     │              │      │          │ │    query     │       │
"  https:   //    user   :   pass   @ sub.host.com : 8080   /p/a/t/h  ?  query=string   #hash "
│          │  │          │          │   hostname   │ port │          │                │       │
│          │  │          │          ├──────────────┴──────┤          │                │       │
│ protocol │  │ username │ password │        host         │          │                │       │
├──────────┴──┼──────────┴──────────┼─────────────────────┤          │                │       │
│   origin    │                     │       origin        │ pathname │     search     │ hash  │
├─────────────┴─────────────────────┴─────────────────────┴──────────┴────────────────┴───────┤
│                                            href                                             │
└─────────────────────────────────────────────────────────────────────────────────────────────┘

 

http服务器端 :http.server的事件
1、http.Server 的事件
http.Server 是一个基于事件的 HTTP 服务器,所有的请求都被封装为独立的事件,开发者只需要对它的事件编写
响应函数即可实现 HTTP 服务器的所有功能。它继承自EventEmitter,提供了以下几个事件。
①request:当客户端请求到来时,该事件被触发,提供两个参数 req 和res,分别是http.ServerRequest 和
http.ServerResponse 的实例,表示请求和响应信息。
request.post('', {form:{key:'value'}})
request.post(')
var r = request.post('')
var form = r.form()
form.append('my_field', 'my_value')
form.append('my_buffer', new Buffer([1, 2, 3]))
form.append('my_file', fs.createReadStream(path.join(__dirname, 'doodle.png'))
form.append('remote_file', request(''))
var server =new http.Server();
server.on("request",function(request,response){
//用于接收客户端post过来的数据
var reqJson="";
request.on("data",function(chunk){
reqJson =chunk;
});
request.on("end",function(){
console.log(reqJson);
response.writeHead(200,{
'Content-Type':'text/html'
});
//对接收的数据处理后返回
response.end(reqJson);
})
});
② connection:当 TCP 连接建立时,该事件被触发,提供一个参数 socket,为net.Socket 的实例。
connection 事件的粒度要大于 request,因为客户端在Keep-Alive 模式下可能会在同一个连接内发送多次请
求。
③close :当服务器关闭时,该事件被触发。注意不是在用户连接断开时。除此之外还有 checkContinue、
upgrade、clientError 事件,通常我们不需要关心,只有在实现复杂的 HTTP 服务器的时候才会用到。
在这些事件中, 最常用的就是 request 了, 因此 http 提供了一个捷径:
http.createServer([requestListener]) , 功能是创建一个 HTTP 服务器并将requestListener 作为 request 事
件的监听函数,这也是我们前面例子中使用的方法。
var http = require('http');
/**
* 创建服务器的两种写法,第一种写法如下
* 由于server已经继承了EventEmitter的事件功能,所以可以使用高级函数编写方式监控事件
* @param {Function} request event
*/
var server = http.createServer(function(req,res)
{
//这里的req为http.serverRequest
res.writeHeader(200,{'Content-Type':'text/plain'});
res.end('hello world');
});
/**
* 说明:创建服务器的第二种写法
* 有关server对象的事件监听
* @param {Object} req 是http.IncomingMessag的一个实例,在keep-alive连接中支持多个请求
* @param {Object} res 是http.ServerResponse的一个实例
*/
var server = new http.Server();
server.on('request',function(req,res){
res.writeHeader(200,{'Content-Type':'text/plain'});
res.end('hello world');
});
/**
* 说明:新的TCP流建立时出发。 socket是一个net.Socket对象。 通常用户无需处理该事件。
* 特别注意,协议解析器绑定套接字时采用的方式使套接字不会出发readable事件。 还可以通过
request.connection访问socket。
* @param {Object} socket
*/
server.on('connection',function(socket){});
/**
* 源API: Event: 'close'
* 说明:关闭服务器时触发
*/
server.on('close',function(){});
/**
* 说明:每当收到Expect: 100-continue的http请求时触发。 如果未监听该事件,服务器会酌情自动发送100
Continue响应。
* 处理该事件时,如果客户端可以继续发送请求主体则调用response.writeContinue, 如果不能则生成合适的HTTP
响应(例如,400 请求无效)
* 需要注意到, 当这个事件触发并且被处理后, request 事件将不再会触发.
* @param {Object} req
* @param {Object} req
*/
server.on('checkContinue',function(req,res){});
/**
* 说明:如果客户端发起connect请求,如果服务器端没有监听,那么于客户端请求的该连接将会被关闭
* @param {Object} req 是该HTTP请求的参数,与request事件中的相同。
* @param {Object} socket 是服务端与客户端之间的网络套接字。需要自己写一个data事件监听数据流
* @param {Object} head 是一个Buffer实例,隧道流的第一个包,该参数可能为空。
*/
server.on('connect',function(req,socket,head){});
/**
* 说明:这个事件主要是对HTTP协议升级为其他协议后的事件监听,如果服务器端没有监听,那么于客户端请求的该连
接将会被关闭
* @param {Object} req 是该HTTP请求的参数,与request事件中的相同。
* @param {Object} socket 是服务端与客户端之间的网络套接字。需要自己写一个data事件监听数据流
* @param {Object} head 是一个Buffer实例,升级后流的第一个包,该参数可能为空。
*/
server.on('upgrade',function(req,socket,head){});
/**
* 说明:如果一个客户端连接触发了一个 'error' 事件, 它就会转发到这里
* @param {Object} exception
* @param {Object} socket
*/
server.on('clientError',function(exception,socket){});
/**
* 源API:server.listen(port, [hostname], [backlog], [callback])
* 说明:监听一个 unix socket, 需要提供一个文件名而不是端口号和主机名。
* @param {Number} port 端口
* @param {String} host 主机
* @param {Number} backlog 等待队列的最大长度,决定于操作系统平台,默认是511
* @param {Function} callback 异步回调函数
*/
//server.listen(3000,'localhost',100,function(){});
/**
* 源API:server.listen(path, [callback])
* 说明:启动一个 UNIX 套接字服务器在所给路径 path 上监听连接。
* 可能用处:多路径或渠道数据来源监听分隔
* @param {String} path
* @param {Function} callback
*/
//server.listen('path',function(){})
/**
* 源API:server.listen(handle, [callback])
* 说明:Windows 不支持监听一个文件描述符。
* @param {Object} handle 变量可以被设置为server 或者 socket
* @param {Function} callback
*/
//server.listen({},function(){});
/**
* 说明:最大请求头数目限制, 默认 1000 个. 如果设置为0, 则代表不做任何限制.
* @type {number}
*/
server.maxHeadersCount = 1000;
/**
* 源API:server.setTimeout(msecs, callback)
* 说明:为套接字设定超时值。如果一个超时发生,那么Server对象上会分发一个'timeout'事件,同时将套接字作为
参数传递。
* 设置为0将阻止之后建立的连接的一切自动超时行为
* @param {Number} msecs
* @param
*/
server.setTimeout(1000,function(){});
/**
* 说明:一个套接字被判断为超时之前的闲置毫秒数。 默认 120000 (2 分钟)
* @type {number}
*/
server.timeout = 120000;
/**
* 说明:这里的主机将是本地
* @param {Number} port 端口
* @param {Function} callback 异步回调函数
*/
server.listen(3000,function(){
console.log('Listen port 3000');
});
var https = require('https');
var zlib = require('zlib');
var post_data="………………";//请求数据
var reqdata = JSON.stringify(post_data);
var options = {
hostname: '10.225.***.***',
port: '8443',
path: '/data/table/list',
method: 'POST',
rejectUnauthorized: false,
requestCert: true,
nodejs 简单http 文件上传
auth: 'admin:123456************',
headers: {
'username': 'admin',
'password': '123456************',
'Cookie': 'locale=zh_CN',
'X-BuildTime': '2015-01-01 20:04:11',
'Autologin': '4',
'Accept-Encoding': 'gzip, deflate',
'X-Timeout': '3600000',
'Content-Type': 'Application/json',
"Content-Length":reqdata.length
}
};
var req = https.request(options, function (res) {
});
req.write(reqdata);
req.on('response', function (response) {
switch (response.headers['content-encoding']) {
case 'gzip':
var body = '';
var gunzip = zlib.createGunzip();
response.pipe(gunzip);
gunzip.on('data', function (data) {
body = data;
});
gunzip.on('end', function () {
var returndatatojson= JSON.parse(body);
req.end();
});
gunzip.on('error', function (e) {
console.log('error' e.toString());
req.end();
});
break;
case 'deflate':
var output = fs.createWriteStream("d:temp.txt");
response.pipe(zlib.createInflate()).pipe(output);
req.end();
break;
default:req.end();
break;
}
});
req.on('error', function (e) {
console.log(new Error('problem with request: ' e.message));
req.end();
setTimeout(cb, 10);
});
// 这是一个简单的Node HTTP,能处理当前目录的文件
// 并能实现良种特殊的URL用于测试
// 用 或 连接这个服务器
// 首先,加载所有要用的模块
var http = require('http'); // HTTP服务器API
var fs = require('fs'); // 文件系统API
var server = new http.Server(); // 创建新的HTTP服务器
var port = 8000;
server.listen(port); // 在端口8000伤运行它
var log = require('util').log;
log('Http Server is listening ' port ' port.');
// Node使用'on'方法注册事件处理程序
// 当服务器收到新请求,则运行函数处理它
server.on('request', function(request, response) {
var filename = null;
// 解析请求的URL
var url = require('url').parse(request.url);
switch(url.pathname) {
case '/upload':
var _fileName = request.headers['file-name'];
log(_fileName);
request.once('data', function(data) {
// 大文件
// var fis = fs.createWriteStream('/txt.txt');
// fis.write(data);
// fis.end();
fs.writeFile(_fileName, data);
response.end();
});
break;
case '/' || '/index.html' :
filename = 'index.html';
default:
filename = filename || url.pathname.substring(1); // 去掉前导'/'
// 基于其扩展名推测内容类型
var type = (function(_type) {
switch(_type) { // 扩展名
case 'html':
case 'htm': return 'text/html; charset=UTF-8';
case 'js': return 'application/javascript; charset=UTF-8';
case 'css': return 'text/css; charset=UTF-8';
case 'txt': return 'text/plain; charset=UTF-8';
case 'manifest': return 'text/cache-manifest; charset=UTF-8';
default: return 'application/octet-stream';
}
}(filename.substring(filename.lastIndexOf('.') 1)));
// 异步读取文件,并将内容作为单独的数据块传回给回调函数
// 对于确实很大的文件,使用API fs.createReadStream()更好
fs.readFile(filename, function(err, content) {
if (err) { // 如果由于某些原因无法读取文件
response.writeHead(404, {'Content-type' : 'text/plain; charset=UTF-8'});
response.write(err.message);

} else { // 否则读取文件成功
response.writeHead(200, {'Content-type' : type});
response.write(content); // 把文件内容作为响应主体
}
response.end();
});
}
});

2、http.ServerRequest
http.ServerRequest 是 HTTP 请求的信息,是后端开发者最关注的内容。它一般由http.Server 的 request
事件发送,作为第一个参数传递,通常简称 request 或 req。
HTTP 请求一般可以分为两部分:请求头(Request Header)和请求体(Requset Body)。以上内容由于长
度较短都可以在请求头解析完成后立即读取。而请求体可能相对较长,需要一定的时间传输。
http.ServerRequest 提供了以下3个事件用于控制请求体传输。
data :当请求体数据到来时,该事件被触发。该事件提供一个参数 chunk,表示接收到的数据。如果该事件
没有被监听,那么请求体将会被抛弃。该事件可能会被调用多次。
end :当请求体数据传输完成时,该事件被触发,此后将不会再有数据到来。
close: 用户当前请求结束时,该事件被触发。不同于 end,如果用户强制终止了传输,也还是调用close。

 

 

 

var count = files.length;

在正式开始Node.js学习之前,我们先认识一下npm。

6. 单进程,单线程

url:用于解析URL。

因为JavaScript是单线程执行,根本不能进行同步IO操作,所以,JavaScript的这一“缺陷”导致了它只能使用异步IO。

基本用法

Node使用CommonJS模块规范,内置的require命令用于加载模块文件。

require命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的exports对象。如果没有发现指定模块,会报错。

// example.js
var invisible = function () {
  console.log("invisible");
}

exports.message = "hi";

exports.say = function () {
  console.log(message);
}

运行下面的命令,可以输出exports对象。

var example = require('./example.js');
example
// {
//   message: "hi",
//   say: [Function]
// }

如果模块输出的是一个函数,那就不能定义在exports对象上面,而要定义在module.exports变量上面。

module.exports = function () {
  console.log("hello world")
}

require('./example2.js')()

上面代码中,require命令调用自身,等于是执行module.exports,因此会输出 hello world。

 

使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。

环境变量NODE_PATH

Node执行一个脚本时,会先查看环境变量NODE_PATH。它是一组以冒号分隔的绝对路径。在其他位置找不到指定模块时,Node会去这些路径查找。

可以将NODE_PATH添加到.bashrc

export NODE_PATH="/usr/local/lib/node"

所以,如果遇到复杂的相对路径,比如下面这样。

var myModule = require('../../../../lib/myModule');

有两种解决方法,一是将该文件加入node_modules目录,二是修改NODE_PATH环境变量,package.json文件可以采用下面的写法。

{
  "name": "node_path",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "NODE_PATH=lib node index.js"
  },
  "author": "",
  "license": "ISC"
}

NODE_PATH是历史遗留下来的一个路径解决方案,通常不应该使用,而应该使用node_modules目录机制。

 

node-interactive-env

>3NodeJS的优缺点

.. 

我们把hello.js改造一下,创建一个函数,这样我们就可以在其他地方调用这个函数:

2. 依赖于Chrome V8引擎进行代码解释

模块**
**

console.log(100 200 300);

>1.旨在提供一种简单的构建可伸缩网络程序的方法

 

引入的模块作为变量保存在greet变量中,那greet变量到底是什么东西?其实变量greet就是在hello.js中我们用module.exports

greet;输出的greet函数。所以,main.js就成功地引用了hello.js模块中定义的greet()函数,接下来就可以直接使用它了。

在使用require()引入模块的时候,请注意模块的相对路径。因为main.js

和hello.js位于同一个目录,所以我们用了当前目录.:

vargreet =require('./hello');// 不要忘了写相对目录!

如果只写模块名:

vargreet =require('hello');

则Node会依次在内置模块、全局模块和当前模块下查找hello.js,你很可能会得到一个错误:

module.js throw err; ^Error: Cannot find module 'hello' at

Function.Module._resolveFilename at Function.Module._load ... at

Function.Module._load at Function.Module.runMain

遇到这个错误,你要检查:

模块名是否写对了

模块文件是否存在

相对路径是否写对了

CommonJS规范

这种模块加载机制被称为CommonJS规范。在这个规范下,每个.js文件都是一个模块,它们内部各自使用的变量名和函数名都互不冲突,例如,hello.js

和main.js都申明了全局变量var s = 'xxx',但互不影响。

一个模块想要对外暴露变量(函数也是变量),可以用module.exports = variable;,一个模块要引用其他模块暴露的变量,用

varref =require('module_name');

就拿到了引用模块的变量。

要在模块中对外输出变量,用:module.exports = variable;

输出的变量可以是任意对象、函数、数组等等。要引入其他模块输出的对象,用:var foo = require('other_module');

引入的对象具体是什么,取决于引入模块输出的对象。

深入了解模块原理

如果你想详细地了解CommonJS的模块实现原理,请继续往下阅读

当我们编写JavaScript代码时,我们可以申明全局变量:

vars ='global';

在浏览器中,大量使用全局变量可不好。如果你在a.js中使用了全局变量s,那么,在b.js中也使用全局变量s,将造成冲突,b.js中对s赋值会改变a.js的运行逻辑。

也就是说,JavaScript语言本身并没有一种模块机制来保证不同模块可以使用相同的变量名。

那Node.js是如何实现这一点的?

其实要实现“模块”这个功能,并不需要语法层面的支持。Node.js也并不会增加任何JavaScript语法。实现“模块”功能的奥妙就在于JavaScript是一种函数式编程语言,它支持闭包。如果我们把一段JavaScript代码用一个函数包装起来,这段代码的所有“全局”变量就变成了函数内部的局部变量。

请注意我们编写的hello.js代码是这样的:

vars ='Hello';varname ='world';console.log(s ' ' name '!');

Node.js加载了hello.js后,它可以把代码包装一下,变成这样执行:

(function(){// 读取的hello.js代码:vars ='Hello';varname ='world';console.log(s ' ' name '!');// hello.js代码结束})();

这样一来,原来的全局变量s现在变成了匿名函数内部的局部变量。如果Node.js继续加载其他模块,这些模块中定义的“全局”变量s也互不干扰。

所以,Node利用JavaScript的函数式编程的特性,轻而易举地实现了模块的隔离。

但是,模块的输出module.exports怎么实现?

这个也很容易实现,Node可以先准备一个对象module:

// 准备module对象:varmodule= {id:'hello',exports: {}};varload =function(module){// 读取的hello.js代码:functiongreet(name){console.log('Hello, ' name '!');  }module.exports = greet;// hello.js代码结束returnmodule.exports;};varexported = load(module);// 保存module:save(module, exported);

可见,变量module是Node在加载js文件前准备的一个变量,并将其传入加载函数,我们在hello.js中可以直接使用变量module原因就在于它实际上是函数的一个参数:module.exports = greet;

通过把参数module传递给load()函数,hello.js就顺利地把一个变量传递给了Node执行环境,Node会把module变量保存到某个地方。

由于Node保存了所有导入的module,当我们用require()获取module时,Node找到对应的module,把这个module的exports变量返回,这样,另一个模块就顺利拿到了模块的输出:

vargreet =require('./hello');

以上是Node实现JavaScript模块的一个简单的原理介绍。

module.exports vs exports

很多时候,你会看到,在Node环境中,有两种方法可以在一个模块中输出变量:

方法一:对module.exports赋值:

// hello.jsfunctionhello(){console.log('Hello, world!');}functiongreet(name){console.log('Hello, ' name '!');}functionhello(){console.log('Hello, world!');}module.exports = {hello: hello,greet: greet};

方法二:直接使用exports:

// hello.jsfunctionhello(){console.log('Hello, world!');}functiongreet(name){console.log('Hello, ' name '!');}functionhello(){console.log('Hello, world!');}exports.hello = hello;exports.greet = greet;

但是你不可以直接对exports赋值:

// 代码可以执行,但是模块并没有输出任何变量:exports = {hello: hello,greet: greet};

如果你对上面的写法感到十分困惑,不要着急,我们来分析Node的加载机制:

首先,Node会把整个待加载的hello.js文件放入一个包装函数load中执行。在执行这个load()函数前,Node准备好了module变量:

varmodule= {id:'hello',exports: {}};

load()函数最终返回module.exports:

varload =function(exports, module){// hello.js的文件内容 ...// load函数返回:returnmodule.exports;};varexported = load(module.exports,module);

也就是说,默认情况下,Node准备的exports变量和module.exports变量实际上是同一个变量,并且初始化为空对象{},于是,我们可以写:

exports.foo =function(){return'foo'; };exports.bar =function(){return'bar'; };

也可以写:

module.exports.foo =function(){return'foo'; };module.exports.bar =function(){return'bar'; };

换句话说,Node默认给你准备了一个空对象{},这样你可以直接往里面加东西。

但是,如果我们要输出的是一个函数或数组,那么,只能给module.exports

赋值:

module.exports =function(){return'foo'; };

给exports赋值是无效的,因为赋值后,module.exports仍然是空对象{}。

结论:

如果要输出一个键值对象{},可以利用exports这个已存在的空对象{},并继续在上面添加新的键值;

如果要输出一个函数或数组,必须直接对module.exports对象赋值。

所以我们可以得出结论:直接对module.exports赋值,可以应对任何情况:

module.exports = {foo:function(){return'foo';  }};

或者:

module.exports =function(){return'foo'; };

最终,我们强烈建议使用module.exports = xxx的方式来输出模块变量,这样,你只需要记忆一种方法。

基本模块

因为Node.js是运行在服务区端的JavaScript环境,服务器程序和浏览器程序相比,最大的特点是没有浏览器的安全限制了,而且,服务器程序必须能接收网络请求,读写文件,处理二进制内容,所以,Node.js内置的常用模块就是为了实现基本的服务器功能。这些模块在浏览器环境中是无法被执行的,因为它们的底层代码是用C/C 在Node.js运行环境中实现的。

global

在前面的JavaScript课程中,我们已经知道,JavaScript有且仅有一个全局对象,在浏览器中,叫window对象。而在Node.js环境中,也有唯一的全局对象,但不叫window,而叫global,这个对象的属性和方法也和浏览器环境的window不同。进入Node.js交互环境,可以直接输入:

> global.console

Console {

log: [Function: bound ],

info: [Function: bound ],

warn: [Function: bound ],

error: [Function: bound ],

dir: [Function: bound ],

time: [Function: bound ],

timeEnd: [Function: bound ],

trace: [Function: bound trace],

assert: [Function: bound ],

Console: [Function: Console] }

process

process也是Node.js提供的一个对象,它代表当前Node.js进程。通过process对象可以拿到许多有用信息:

> process === global.process;

true

> process.version;

'v5.2.0'

> process.platform;

'darwin'

> process.arch;

'x64'

> process.cwd(); //返回当前工作目录

'/Users/michael'

> process.chdir('/private/tmp'); // 切换当前工作目录

undefined

> process.cwd();

'/private/tmp'

JavaScript程序是由事件驱动执行的单线程模型,Node.js也不例外。Node.js不断执行响应事件的JavaScript函数,直到没有任何响应事件的函数可以执行时,Node.js就退出了。

如果我们想要在下一次事件响应中执行代码,可以调用process.nextTick():

// test.js// process.nextTick()将在下一轮事件循环中调用:process.nextTick(function(){console.log('nextTick callback!');});console.log('nextTick was set!');

用Node执行上面的代码node test.js,你会看到,打印输出是:

nextTick was set!

nextTick callback!

这说明传入process.nextTick()的函数不是立刻执行,而是要等到下一次事件循环。

Node.js进程本身的事件就由process对象来处理。如果我们响应exit事件,就可以在程序即将退出时执行某个回调函数:

// 程序即将退出时的回调函数:process.on('exit',function(code){console.log('about to exit with code: ' code);});

判断JavaScript执行环境

有很多JavaScript代码既能在浏览器中执行,也能在Node环境执行,但有些时候,程序本身需要判断自己到底是在什么环境下执行的,常用的方式就是根据浏览器和Node环境提供的全局变量名称来判断:

if(typeof(window) ==='undefined') {console.log('node.js');}else{console.log('browser');}

后面,我们将介绍Node.js的常用内置模块。

fs

Node.js内置的fs模块就是文件系统模块,负责读写文件。

和所有其它JavaScript模块不同的是,fs模块同时提供了异步和同步的方法。

回顾一下什么是异步方法。因为JavaScript的单线程模型,执行IO操作时,JavaScript代码无需等待,而是传入回调函数后,继续执行后续JavaScript代码。比如jQuery提供的getJSON()操作:

$.getJSON('...');

而同步的IO操作则需要等待函数返回:

// 根据网络耗时,函数将执行几十毫秒~几秒不等:vardata = getJSONSync('');

同步操作的好处是代码简单,缺点是程序将等待IO操作,在等待时间内,无法响应其它任何事件。而异步读取不用等待IO操作,但代码较麻烦。

异步读文件

按照JavaScript的标准,异步读取一个文本文件的代码如下:

'use strict';varfs =require('fs');fs.readFile('sample.txt','utf-8',function(err, data){if(err) {console.log(err);  }else{console.log(data);  }});

请注意,sample.txt文件必须在当前目录下,且文件编码为utf-8。

异步读取时,传入的回调函数接收两个参数,当正常读取时,err参数为null,data参数为读取到的String。当读取发生错误时,err参数代表一个错误对象,data为undefined。

这也是Node.js标准的回调函数:第一个参数代表错误信息,第二个参数代表结果。后面我们还会经常编写这种回调函数。

由于err是否为null就是判断是否出错的标志,所以通常的判断逻辑总是:

if(err) {// 出错了}else{// 正常}

如果我们要读取的文件不是文本文件,而是二进制文件,怎么办?

下面的例子演示了如何读取一个图片文件:

'use strict';varfs =require('fs');fs.readFile('sample.png',function(err, data){if(err) {console.log(err);  }else{console.log(data);console.log(data.length ' bytes');  }});

当读取二进制文件时,不传入文件编码时,回调函数的data参数将返回一个Buffer对象。在Node.js中,Buffer对象就是一个包含零个或任意个字节的数组(注意和Array不同)。

Buffer对象可以和String作转换,例如,把一个Buffer对象转换成String:

// Buffer -> Stringvartext = data.toString('utf-8');console.log(text);

或者把一个String转换成Buffer:

// String -> Buffervarbuf =newBuffer(text,'utf-8');console.log(buf);

同步读文件

除了标准的异步读取模式外,fs也提供相应的同步读取函数。同步读取的函数和异步函数相比,多了一个Sync后缀,并且不接收回调函数,函数直接返回结果。

用fs模块同步读取一个文本文件的代码如下:

'use strict';varfs =require('fs');vardata = fs.readFileSync('sample.txt','utf-8');console.log(data);

可见,原异步调用的回调函数的data被函数直接返回,函数名需要改为readFileSync,其它参数不变。

如果同步读取文件发生错误,则需要用try...catch捕获该错误:

try{vardata = fs.readFileSync('sample.txt','utf-8');console.log(data);}catch(err) {// 出错了}

写文件

将数据写入文件是通过fs.writeFile()实现的:

'use strict';varfs =require('fs');vardata ='Hello, Node.js';fs.writeFile('output.txt', data,function(err){if(err) {console.log(err);  }else{console.log('ok.');  }});

writeFile()的参数依次为文件名、数据和回调函数。如果传入的数据是String,默认按UTF-8编码写入文本文件,如果传入的参数是Buffer,则写入的是二进制文件。回调函数由于只关心成功与否,因此只需要一个err参数。

和readFile()类似,writeFile()也有一个同步方法,叫writeFileSync():

'use strict';varfs =require('fs');vardata ='Hello, Node.js';fs.writeFileSync('output.txt', data);

stat

如果我们要获取文件大小,创建时间等信息,可以使用fs.stat(),它返回一个Stat对象,能告诉我们文件或目录的详细信息:

'use strict';varfs =require('fs');fs.stat('sample.txt',function(err, stat){if(err) {console.log(err);  }else{// 是否是文件:console.log('isFile: ' stat.isFile());// 是否是目录:console.log('isDirectory: ' stat.isDirectory());if(stat.isFile()) {// 文件大小:console.log('size: ' stat.size);// 创建时间, Date对象:console.log('birth time: ' stat.birthtime);// 修改时间, Date对象:console.log('modified time: ' stat.mtime);    }  }});

运行结果如下:

isFile: true

isDirectory: false

size: 181

birth time: Fri Dec 11 2015 09:43:41 GMT 0800 (CST)

modified time: Fri Dec 11 2015 12:09:00 GMT 0800 (CST)

stat()也有一个对应的同步函数statSync(),请试着改写上述异步代码为同步代码。

异步还是同步

在fs模块中,提供同步方法是为了方便使用。那我们到底是应该用异步方法还是同步方法呢?

由于Node环境执行的JavaScript代码是服务器端代码,所以,绝大部分需要在服务器运行期反复执行业务逻辑的代码,必须使用异步代码,否则,同步代码在执行时期,服务器将停止响应,因为JavaScript只有一个执行线程。

服务器启动时如果需要读取配置文件,或者结束时需要写入到状态文件时,可以使用同步代码,因为这些代码只在启动和结束时执行一次,不影响服务器正常运行时的异步执行。

stream

stream是Node.js提供的又一个仅在服务区端可用的模块,目的是支持“流”这种数据结构。

什么是流?流是一种抽象的数据结构。想象水流,当在水管中流动时,就可以从某个地方(例如自来水厂)源源不断地到达另一个地方(比如你家的洗手池)。

我们也可以把数据看成是数据流,比如你敲键盘的时候,就可以把每个字符依次连起来,看成字符流。这个流是从键盘输入到应用程序,实际上它还对应着一个名字:标准输入流(stdin)。

如果应用程序把字符一个一个输出到显示器上,这也可以看成是一个流,这个流也有名字:标准输出流(stdout)。流的特点是数据是有序的,而且必须依次读取,或者依次写入,不能像Array那样随机定位。

分分快三计划 2

nodejs-stream

有些流用来读取数据,比如从文件读取数据时,可以打开一个文件流,然后从文件流中不断地读取数据。有些流用来写入数据,比如向文件写入数据时,只需要把数据不断地往文件流中写进去就可以了。

在Node.js中,流也是一个对象,我们只需要响应流的事件就可以了:data事件表示流的数据已经可以读取了,end事件表示这个流已经到末尾了,没有数据可以读取了,error事件表示出错了。

下面是一个从文件流读取文本内容的示例:

'use strict';varfs =require('fs');// 打开一个流:varrs = fs.createReadStream('sample.txt','utf-8');rs.on('data',function(chunk){console.log('DATA:')console.log(chunk);});rs.on('end',function(){console.log('END');});rs.on('error',function(err){console.log('ERROR: ' err);});

要注意,data事件可能会有多次,每次传递的chunk是流的一部分数据。

要以流的形式写入文件,只需要不断调用write()方法,最后以end()结束:

'use strict';varfs =require('fs');varws1 =

不讨论这种架构是好是坏,但是有另外一种实践,面向服务的架构,更好的做前后端的依赖分离。如果所有的关键业务逻辑都封装成REST调用,就意味着在上层只需要考虑如何用这些REST接口构建具体的应用。那些后端程序员们根本不操心具体数据是如何从一个页面传递到另一个页面的,他们也不用管用户数据更新是通过Ajax异步获取的还是通过刷新页面。

读一点数据,处理一点点数据(读到有限长的buffer中,然后再读取出来,)

C:Workspace>node calc.js

  1. nodejs

dirinfo.forEach(info=>{

$ node -vv6.2.0

这是NodeJS最理想的应用场景,可以处理数万条连接,本身没有太多的逻辑,只需要请求API,组织数据进行返回即可。它本质上只是从某个数据库中查找一些值并将它们组成一个响应。由于响应是少量文本,入站请求也是少量的文本,因此流量不高,一台机器甚至也可以处理最繁忙的公司的API需求。

分分快三计划 3

请注意,用哪个都行,但是绝对不能用Word和写字板,Windows自带的记事本也强烈不推荐使用。Word和写字板保存的不是纯文本文件,而记事本会自作聪明地在文件开始的地方加上几个特殊字符(UTF-8 BOM),结果经常会导致程序运行出现莫名其妙的错误。

module.exports属性

module.exports属性表示当前模块对外输出的接口,其他文件加载该模块,实际上就是读取module.exports变量。

var EventEmitter = require('events').EventEmitter;
module.exports = new EventEmitter();

setTimeout(function() {
  module.exports.emit('ready');
}, 1000);

上面模块会在加载后1秒后,发出ready事件。其他文件监听该事件,可以写成下面这样。

var a = require('./a');
a.on('ready', function() {
  console.log('module a is ready');
});

 

但是,写一个calc.js的文件,内容如下:

Node.js 是一个基于Chromev8 JavaScript 运行时建立的一个平台, 用来方便地搭建快速的, 易于扩展的网络应用· Node.js 借助事件驱动, 非阻塞 I/O 模型变得轻量和高效

 

C:UsersIEUser>node -vv6.2.0

原因:单进程,单线程

Buffer

是因为我们总是以严格模式运行JavaScript代码,避免各种潜在陷阱。然后,选择一个目录,例如C:Workspace,把文件保存为hello.js,就可以打开命令行窗口,把当前目录切换到hello.js所在目录,然后输入以下命令运行这个程序了:

目前MVC的架构,在某种意义上来说,Web开发有两个UI层,一个是在浏览器里面我们最终看到的,另一个在server端,负责生成和拼接页面。

if(stats.isFile()){

为啥我们需要一个包管理工具呢?因为我们在Node.js上开发时,会用到很多别人写的JavaScript代码。如果我们要使用别人写的某个包,每次都根据名称搜索一下官方网站,下载代码,解压,再使用,非常繁琐。于是一个集中管理的工具应运而生:大家都把自己开发的模块打包后放到npm官网上,如果要使用,直接通过npm安装就可以直接用,不用管代码存在哪,应该从哪下载。

优点:

var target = path.join(__dirname,'./');

npm是什么东东?npm其实是Node.js的包管理工具(package manager)。

require命令

在回调函数中对buffer进行tostring转换,然后split掉'n',对于数组中的每一行,用正则提取时间,然后settimeout按时间显示出来

继续在命令提示符输入node,此刻你将进入Node.js的交互环境。在交互环境下,你可以输入任意JavaScript语句,例如100 200,回车后将得到输出结果。

1. 高并发(最重要的优点)

const filename = path.join(__dirname,id);

其次,JavaScript语言本身是完善的函数式语言,在前端开发时,开发人员往往写得比较随意,让人感觉JavaScript就是个“玩具语言”。但是,在Node环境下,通过模块化的JavaScript代码,加上函数式编程,并且无需考虑浏览器兼容性问题,直接使用最新的ECMAScript 6标准,可以完全满足工程上的需求。

3. 可靠性低,一旦代码某个环节崩溃,整个系统都崩溃

 

在上一节,我们编写了一个hello.js文件,这个hello.js文件就是一个模块,模块的名字就是文件名(去掉.js后缀),所以hello.js文件就是名为hello的模块。

1. 它是一个Javascript运行环境

 

讲了这么多,npm究竟在哪?

2. 适合I/O密集型应用

}else{

请注意区分命令行模式和Node交互模式。看到类似C:>是在Windows提供的命令行模式:

2. 统一Web应用的UI层

rl.on('line',(line)=>{....对line进行处理})

函数greet()是我们在hello模块中定义的,你可能注意到最后一行是一个奇怪的赋值语句,它的意思是,把函数greet作为模块的输出暴露出去,这样其他模块就可以使用greet函数了。

exports变量

为了方便,Node为每个模块提供一个exports变量,指向module.exports。这等同在每个模块头部,有一行这样的命令。

var exports = module.exports;

造成的结果是,在对外输出模块接口时,可以向exports对象添加方法。

exports.area = function (r) {
  return Math.PI * r * r;
};

exports.circumference = function (r) {
  return 2 * Math.PI * r;
};

注意,不能直接将exports变量指向一个值,因为这样等于切断了exportsmodule.exports的联系。

exports = function(x) {console.log(x)};

上面这样的写法是无效的,因为exports不再指向module.exports了。

下面的写法也是无效的。

exports.hello = function() {
  return 'hello';
};

module.exports = 'Hello world';

上面代码中,hello函数是无法对外输出的,因为module.exports被重新赋值了。

这意味着,如果一个模块的对外接口,就是一个单一的值,不能使用exports输出,只能使用module.exports输出。

module.exports = function (x){ console.log(x);};

如果你觉得,exportsmodule.exports之间的区别很难分清,一个简单的处理方法,就是放弃使用exports,只使用module.exports

}

发现什么输出都没有。这是正常的。想要输出结果,必须自己用console.log()打印出来。把calc.js改造一下:

模块的缓存

第一次加载某个模块时,Node会缓存该模块。以后再加载该模块,就直接从缓存取出该模块的module.exports属性。

require('./example.js');
require('./example.js').message = "hello";
require('./example.js').message
// "hello"

上面代码中,连续三次使用require命令,加载同一个模块。第二次加载的时候,为输出的对象添加了一个message属性。但是第三次加载的时候,这个message属性依然存在,这就证明require命令并没有重新加载模块文件,而是输出了缓存。

如果想要多次执行某个模块,可以让该模块输出一个函数,然后每次require这个模块的时候,重新执行一下输出的函数。

所有缓存的模块保存在require.cache之中,如果想删除模块的缓存,可以像下面这样写。

// 删除指定模块的缓存
delete require.cache[moduleName];

// 删除所有模块的缓存
Object.keys(require.cache).forEach(function(key) {
  delete require.cache[key];
})

注意,缓存是根据绝对路径识别模块的,如果同样的模块名,但是保存在不同的路径,require命令还是会重新加载该模块。

方法1.fs.writeFile(path,callback);

浏览器大战和Node有何关系?

5. 轻量、可伸缩,适于实时数据交互应用

streamReader.on('end',function(){console.log(data);  };  

一个是Sublime Text,免费使用,但是不付费会弹出提示框:

module对象

Node内部提供一个Module构建函数。所有模块都是Module的实例。

function Module(id, parent) {
  this.id = id;
  this.exports = {};
  this.parent = parent;
  // ...

每个模块内部,都有一个module对象,代表当前模块。它有以下属性。

  • module.id 模块的识别符,通常是带有绝对路径的模块文件名。
  • module.filename 模块的文件名,带有绝对路径。
  • module.loaded 返回一个布尔值,表示模块是否已经完成加载。
  • module.parent 返回一个对象,表示调用该模块的模块。
  • module.children 返回一个数组,表示该模块要用到的其他模块。
  • module.exports 表示模块对外输出的值。

下面是一个示例文件,最后一行输出module变量。

// example.js
var jquery = require('jquery');
exports.$ = jquery;
console.log(module);

执行这个文件,命令行会输出如下信息。

{ id: '.',
  exports: { '$': [Function] },
  parent: null,
  filename: '/path/to/example.js',
  loaded: false,
  children:
   [ { id: '/path/to/node_modules/jquery/dist/jquery.js',
       exports: [Function],
       parent: [Circular],
       filename: '/path/to/node_modules/jquery/dist/jquery.js',
       loaded: true,
       children: [],
       paths: [Object] } ],
  paths:
   [ '/home/user/deleted/node_modules',
     '/home/user/node_modules',
     '/home/node_modules',
     '/node_modules' ]
}

如果在命令行下调用某个模块,比如node something.js,那么module.parent就是null。如果是在脚本之中调用,比如require('./something.js'),那么module.parent就是调用它的模块。利用这一点,可以判断当前模块是否为入口脚本。

if (!module.parent) {
    // ran with `node something.js`
    app.listen(8088, function() {
        console.log('app listening on port 8088');
    })
} else {
    // used with `require('/.something.js')`
    module.exports = app;
}

 

vargreet =require('./hello');

2. 只支持单核CPU,不能充分利用CPU

Express框架的核心是对http模块的再包装

具体做法是将来io.js将首先添加新的特性,如果大家测试用得爽,就把新特性加入Node.js。io.js是“尝鲜版”,而Node.js是线上稳定版,相当于Fedora Linux和RHEL的关系。

3. 大量Ajax请求的应用

方法1.用buffer的方式读入fs.readFile(pathxx,callback)

话说有个叫Ryan Dahl的歪果仁,他的工作是用C/C 写高性能Web服务。对于高性能,异步IO、事件驱动是基本原则,但是用C/C 写就太痛苦了。于是这位仁兄开始设想用高级语言开发Web服务。他评估了很多种高级语言,发现很多语言虽然同时提供了同步IO和异步IO,但是开发人员一旦用了同步IO,他们就再也懒得写异步IO了,所以,最终,Ryan瞄向了JavaScript。

加载规则

require命令用于加载文件,后缀名默认为.js

var foo = require('foo');
//  等同于
var foo = require('foo.js');

根据参数的不同格式,require命令去不同路径寻找模块文件。

(1)如果参数字符串以“/”开头,则表示加载的是一个位于绝对路径的模块文件。比如,require('/home/marco/foo.js')将加载/home/marco/foo.js

(2)如果参数字符串以“./”开头,则表示加载的是一个位于相对路径(跟当前执行脚本的位置相比)的模块文件。比如,require('./circle')将加载当前脚本同一目录的circle.js

(3)如果参数字符串不以“./“或”/“开头,则表示加载的是一个默认提供的核心模块(位于Node的系统安装目录中),或者一个位于各级node_modules目录的已安装模块(全局安装或局部安装)。

举例来说,脚本/home/user/projects/foo.js执行了require('bar.js')命令,Node会依次搜索以下文件。

  • /usr/local/lib/node/bar.js
  • /home/user/projects/node_modules/bar.js
  • /home/user/node_modules/bar.js
  • /home/node_modules/bar.js
  • /node_modules/bar.js

这样设计的目的是,使得不同的模块可以将所依赖的模块本地化。

(4)如果参数字符串不以“./“或”/“开头,而且是一个路径,比如require('example-module/path/to/file'),则将先找到example-module的位置,然后再以它为参数,找到后续路径。

(5)如果指定的模块文件没有发现,Node会尝试为文件名添加.js.json.node后,再去搜索。.js件会以文本格式的JavaScript脚本文件解析,.json文件会以JSON格式的文本文件解析,.node文件会以编译后的二进制文件解析。

(6)如果想得到require命令加载的确切文件名,使用require.resolve()方法。

res.end('Welcome to the homepage!n');

最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括Node内置的模块和来自第三方的模块。

目录的加载规则

通常,我们会把相关的文件会放在一个目录里面,便于组织。这时,最好为该目录设置一个入口文件,让require方法可以通过这个入口文件,加载整个目录。

在目录中放置一个package.json文件,并且将入口文件写入main字段。下面是一个例子。

// package.json
{ "name" : "some-library",
  "main" : "./lib/some-library.js" }

require发现参数字符串指向一个目录以后,会自动查看该目录的package.json文件,然后加载main字段指定的入口文件。如果package.json文件没有main字段,或者根本就没有package.json文件,则会加载该目录下的index.js文件或index.node文件。

m4.say();

最大的优势是借助JavaScript天生的事件驱动机制加V8高性能引擎,使编写高性能Web服务轻而易举。

1. 不适合CPU密集型应用;CPU密集型应用给Node带来的挑战主要是:由于JavaScript单线程的原因,如果有长时间运行的计算(比如大循环),将会导致CPU时间片不能释放,使得后续I/O无法发起;

if(req.url == '/about'){

命令行模式和Node交互模式

概述

Node 应用由模块组成,采用 CommonJS 模块规范。

每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。

// example.js
var x = 5;
var addX = function (value) {
  return value   x;
};

上面代码中,变量x和函数addX,是当前文件example.js私有的,其他文件不可见。

如果想在多个文件分享变量,必须定义为global对象的属性。

global.warning = true;

上面代码的warning变量,可以被所有文件读取。当然,这样写法是不推荐的。

CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

var x = 5;
var addX = function (value) {
  return value   x;
};
module.exports.x = x;
module.exports.addX = addX;

上面代码通过module.exports输出变量x和函数addX

require方法用于加载模块。

var example = require('./example.js');

console.log(example.x); // 5
console.log(example.addX(1)); // 6

require方法的详细解释参见《Require命令》一节。

CommonJS模块的特点如下。

  • 所有代码都运行在模块作用域,不会污染全局作用域。
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
  • 模块加载的顺序,按照其在代码中出现的顺序。

http:提供http服务器功能。

我还听说过io.js,这又是什么鬼?

AMD规范与CommonJS规范的兼容性

CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。

AMD规范使用define方法定义模块,下面就是一个例子:

define(['package/lib'], function(lib){
  function foo(){
    lib.log('hello world!');
  }

  return {
    foo: foo
  };
});

AMD规范允许输出的模块兼容CommonJS规范,这时define方法需要写成下面这样:

define(function (require, exports, module){
  var someModule = require("someModule");
  var anotherModule = require("anotherModule");

  someModule.doTehAwesome();
  anotherModule.doMoarAwesome();

  exports.asplode = function (){
    someModule.doTehAwesome();
    anotherModule.doMoarAwesome();
  };
});

包(Node package manager):

一个是Notepad ,免费使用,有中文界面:

>2特点

code=`

在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。

>4. 适合NodeJS的场景

 

随后,Google也开始创建自家的浏览器。他们也看中了WebKit内核,于是基于WebKit内核推出了Chrome浏览器。

解决方案:分解大型运算任务为多个小任务,使得运算能够适时释放,不阻塞I/O调用的发起;

const fs = require('fs');

然而中国有句古话,叫做“分久必合,合久必分”。分家后没多久,Joyent公司表示要和解,于是,io.js项目又决定回归Node.js。

var stats = fs.statSync(path.join(target,info))

C:Workspace>node hello.jsmodule.js:338 throw err; ^Error: Cannot find module 'C:Workspacehello.js' at Function.Module._resolveFilename at Function.Module._load at Function.Module.runMain at startup at node.js

 

100 200 300;

:读取文件时没有指定编码默认读取的是一个Buffer(缓冲区)

第一个Node程序

写文件

现代浏览器大战让微软的IE浏览器远远地落后了,因为他们解散了最有经验、战斗力最强的浏览器团队!回过头再追赶却发现,支持HTML5的WebKit已经成为手机端的标准了,IE浏览器从此与主流移动端设备绝缘。

});

用文本编辑器写JavaScript程序,然后保存为后缀为.js的文件,就可以用node直接运行这个程序了。

在这里对data进行处理

例如,在Node交互式环境下,输入:

crypto:提供加密和解密功能。

先是Mozilla借助已壮烈牺牲的Netscape遗产在2002年推出了Firefox浏览器,紧接着Apple于2003年在开源的KHTML浏览器的基础上推出了WebKit内核的Safari浏览器,不过仅限于Mac平台。

也可以这样写:(将地址写在第一个参数里,这样只有对这个地址的请求,才有相应的回应)

那么问题来了:文本编辑器到底哪家强?

1.process.argv 用于获取当前进程信息

为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Node环境中,一个.js文件就称之为一个模块(module)。

}

在Node上运行的JavaScript相比其他后端开发语言有何优势?

 

'use strict';// 引入hello模块:vargreet =require('./hello');vars ='Michael';greet(s);// Hello, Michael!

进程

于是在2009年,Ryan正式推出了基于JavaScript语言和V8引擎的开源Web服务器项目,命名为Node.js。虽然名字很土,但是,Node第一次把JavaScript带入到后端服务器开发,加上世界上已经有无数的JavaScript开发人员,所以Node一下子就火了起来。

const path = require('path');

C:Workspace>node calc.js

 

再执行,就可以看到结果:

child_process:新建子线程。

报错的意思就是,没有找到hello.js这个文件,因为文件不存在。这个时候,就要检查一下当前目录下是否有这个文件了。

内置模块:

后来,微软通过IE击败了Netscape后一统桌面,结果几年时间,浏览器毫无进步。(2001年推出的古老的IE 6到今天仍然有人在使用!)

res.writeHead(404,{'Content-Type':'text/plain'});

> 100 200 300;

});

模块

写一个require的实现:

Chrome浏览器是跨Windows和Mac平台的,并且,Google认为要运行现代Web应用,浏览器必须有一个性能非常强劲的JavaScript引擎,于是Google自己开发了一个高性能JavaScript引擎,名字叫V8,以BSD许可证开源。

网络框架

其实npm已经在Node.js安装的时候顺带装好了。我们在命令提示符或者终端输入npm -v,应该看到类似的输出:

var prefix = new Array(depth 1).join('| ');

问题是其他模块怎么使用hello模块的这个greet函数呢?我们再编写一个main.js文件,调用hello模块的greet函数:

console.log(`${prefix}├─${dir}`);

选定了开发语言,还要有运行时引擎。这位仁兄曾考虑过自己写一个,不过明智地放弃了,因为V8就是开源的JavaScript引擎。让Google投资去优化V8,咱只负责改造一下拿来用,还不用付钱,这个买卖很划算。

dirs.push(info);

也可以保存为别的名字,比如first.js,但是必须要以.js结尾。此外,文件名只能是英文字母、数字和下划线的组合。

检查文件、删除、重命名..

要退出Node.js环境,连按两次Ctrl C。

let exports = module.exports;

600

//readfile的方式确实是使用buffer,但是也是一次性读取

注意到引入hello模块用Node提供的require函数:

$require.cache = $require.cache || {};

从本章开始,我们编写的JavaScript代码将不能在浏览器环境中执行了,而是在Node环境中执行,因此,JavaScript代码将直接在你的计算机上以命令行的方式运行,所以,我们要先选择一个文本编辑器来编写JavaScript代码,并且把它保存到本地硬盘的某个目录,才能够执行。

 ${code}

安装Node.js和npm

function $require(id){

然后在命令行模式下执行:

let module = { id:filename,exports:{} };

在Node交互式环境下,我们可以输入JavaScript代码并立刻执行。此外,在命令行模式运行.js文件和在Node交互式环境下直接运行JavaScript代码有所不同。Node交互式环境会把每一行JavaScript代码的结果自动打印出来,但是,直接运行JavaScript文件却不会。

...

C:>npm -v3.8.9

app.use(function(req,res,next){

如果当前目录下没有hello.js这个文件,运行node hello.js就会报错:

});

Node的交互模式和直接运行.js文件有什么区别呢?

streamwriter.write('xxx',callback)        (以流的方式写入,防止在内存中读取过多)

notepad-hello.js

var dirs = [];

hello.js

 

直接输入node进入交互模式,相当于启动了Node解释器,但是等待你一行一行地输入源代码,每输入一行就执行一行。

默认写入是覆盖 ,可以使用append追加

npm

Stream:

'use strict';vars ='Hello';functiongreet(name){console.log(s ', ' name '!');}module.exports = greet;

 

如果直接输入npm,你会看到类似下面的输出:

思路:通过使用fs.readdirSync

目前Node.js的最新版本是6.2.x。首先,从Node.js官网下载对应平台的安装程序,网速慢的童鞋请移步国内镜像。

 

在前面的所有章节中,我们编写的JavaScript代码都是在浏览器中运行的,因此,我们可以直接在浏览器中敲代码,然后直接运行。

fs:操作(CRUD)文件系统。

如果版本号不是v6.2.x,说明Node.js版本不对,后面章节的代码不保证能正常运行,请重新安装最新版本。

 

Hello, world.

module是定义在.js文件中的对象

安装完成后,在Windows环境下,请打开命令提示符,然后输入node -v,如果安装正常,你应该看到v6.2.0这样的输出:

(由于对每一行处理需要耗费几毫秒的时间,可以设置begin=new Date().getTime() 然后在后面的settimeout中设置新的new Date.getTime()-begin 减掉这个时间)

在编写JavaScript代码的时候,完全可以一边在文本编辑器里写代码,一边开一个Node交互式命令窗口,在写代码的过程中,把部分代码粘到命令行去验证,事半功倍!前提是得有个27'的超大显示器!

方法3.使用readline模块,用stream的方式读入 var streamReader = fs.createReadStream(filename);  

Hello world!

');});// 让服务器监听8080端口:server.listen(8080);console.log('Server is running at ');

在命令提示符下运行该程序,可以看到以下输出:

$ node hello.js Server is running at

不要关闭命令提示符,直接打开浏览器输入

http-hello-sample

同时,在命令提示符窗口,可以看到程序打印的请求信息:

GET: /GET: /favicon.ico

这就是我们编写的第一个HTTP服务器程序!

文件服务器

让我们继续扩展一下上面的Web程序。我们可以设定一个目录,然后让Web程序变成一个文件服务器。要实现这一点,我们只需要解析request.url中的路径,然后在本地找到对应的文件,把文件内容发送出去就可以了。

解析URL需要用到Node.js提供的url模块,它使用起来非常简单,通过parse()将一个字符串解析为一个Url对象:

'use strict';varurl =require('url');console.log(url.parse(''));

结果如下:

Url {

protocol: 'http:',

slashes: true,

auth: 'user:pass',

host: 'host.com:8080',

port: '8080',

hostname: 'host.com',

hash: '#hash',

search: '?query=string',

query: 'query=string',

pathname: '/path/to/file',

path: '/path/to/file?query=string',

href: ''

}

处理本地文件目录需要使用Node.js提供的path模块,它可以方便地构造目录:

'use strict';varpath =require('path');// 解析当前目录:varworkDir = path.resolve('.');// '/Users/michael'// 组合完整的文件路径:当前目录 'pub' 'index.html':varfilePath = path.join(workDir,'pub','index.html');// '/Users/michael/pub/index.html'

使用path模块可以正确处理操作系统相关的文件路径。在Windows系统下,返回的路径类似于C:Usersmichaelstaticindex.html,这样,我们就不关心怎么拼接路径了。

最后,我们实现一个文件服务器file_server.js:

'use strict';varfs =require('fs'),      url =require('url'),      path =require('path'),      http =require('http');// 从命令行参数获取root目录,默认是当前目录:varroot = path.resolve(process.argv[2] ||'.');console.log('Static root dir: ' root);// 创建服务器:varserver = http.createServer(function(request, response){// 获得URL的path,类似 '/css/bootstrap.css':varpathname = url.parse(request.url).pathname;// 获得对应的本地文件路径,类似 '/srv/www/css/bootstrap.css':varfilepath = path.join(root, pathname);// 获取文件状态:fs.stat(filepath,function(err, stats){if(!err && stats.isFile()) {// 没有出错并且文件存在:console.log('200 ' request.url);// 发送200响应:response.writeHead(200);// 将文件流导向response:fs.createReadStream(filepath).pipe(response);    }else{// 出错了或者文件不存在:console.log('404 ' request.url);// 发送404响应:response.writeHead(404);      response.end('404 Not Found');    }  });});server.listen(8080);console.log('Server is running at ');

没有必要手动读取文件内容。由于response对象本身是一个Writable Stream,直接用pipe()方法就实现了自动读取文件内容并输出到HTTP响应。

在命令行运行node file_server.js /path/to/dir,把/path/to/dir改成你本地的一个有效的目录,然后在浏览器中输入

http-index-page

只要当前目录下存在文件index.html,服务器就可以把文件内容发送给浏览器。观察控制台输出:

200 /index.html

200 /css/uikit.min.css

200 /js/jquery.min.js

200 /fonts/fontawesome-webfont.woff2

第一个请求是浏览器请求index.html页面,后续请求是浏览器解析HTML后发送的其它资源请求。

crypto

crypto模块的目的是为了提供通用的加密和哈希算法。用纯JavaScript代码实现这些功能不是不可能,但速度会非常慢。Nodejs用C/C 实现这些算法后,通过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也快。

MD5和SHA1

MD5是一种常用的哈希算法,用于给任意数据一个“签名”。这个签名通常用一个十六进制的字符串表示:

constcrypto =require('crypto');consthash = crypto.createHash('md5');// 可任意多次调用update():hash.update('Hello, world!');hash.update('Hello, nodejs!');console.log(hash.digest('hex'));// 7e1977739c748beac0c0fd14fd26a544

update()方法默认字符串编码为UTF-8,也可以传入Buffer。

如果要计算SHA1,只需要把'md5'改成'sha1',就可以得到SHA1的结果

1f32b9c9932c02227819a4151feed43e131aca40

还可以使用更安全的sha256和sha512。

Hmac

Hmac算法也是一种哈希算法,它可以利用MD5或SHA1等哈希算法。不同的是,Hmac还需要一个密钥:

constcrypto =require('crypto');consthmac = crypto.createHmac('sha256','secret-key');hmac.update('Hello, world!');hmac.update('Hello, nodejs!');console.log(hmac.digest('hex'));// 80f7e22570...

只要密钥发生了变化,那么同样的输入数据也会得到不同的签名,因此,可以把Hmac理解为用随机数“增强”的哈希算法。

AES

AES是一种常用的对称加密算法,加解密都用同一个密钥。crypto模块提供了AES支持,但是需要自己封装好函数,便于使用:

constcrypto =require('crypto');functionaesEncrypt(data, key){constcipher = crypto.createCipher('aes192', key);varcrypted = cipher.update(data,'utf8','hex');  crypted = cipher.final('hex');returncrypted;}functionaesDecrypt(data, key){constdecipher = crypto.createDecipher('aes192', key);vardecrypted = decipher.update(encrypted,'hex','utf8');  decrypted = decipher.final('utf8');returndecrypted;}vardata ='Hello, this is a secret message!';varkey ='Password!';varencrypted = aesEncrypt(data, key);vardecrypted = aesDecrypt(encrypted, key);console.log('Plain text: ' data);console.log('Encrypted text: ' encrypted);console.log('Decrypted text: ' decrypted);

运行结果如下:

Plain text: Hello, this is a secret message!

Encrypted text: 8a944d97bdabc157a5b7a40cb180e7...

Decrypted text: Hello, this is a secret message!

可以看出,加密后的字符串通过解密又得到了原始内容。

注意到AES有很多不同的算法,如aes192,aes-128-ecb,aes-256-cbc等,AES除了密钥外还可以指定IV(Initial Vector),不同的系统只要IV不同,用相同的密钥加密相同的数据得到的加密结果也是不同的。

加密结果通常有两种表示方法:hex和base64,这些功能Nodejs全部都支持,但是在应用中要注意,如果加解密双方一方用Nodejs,另一方用Java、PHP等其它语言,需要仔细测试。如果无法正确解密,要确认双方是否遵循同样的AES算法,字符串密钥和IV是否相同,加密后的数据是否统一为hex或base64格式。

Diffie-Hellman

DH算法是一种密钥交换协议,它可以让双方在不泄漏密钥的情况下协商出一个密钥来。DH算法基于数学原理,比如小明和小红想要协商一个密钥,可以这么做:

小明先选一个素数和一个底数,例如,素数p=23,底数g=5(底数可以任选),再选择一个秘密整数a=6,计算A=g^a mod p=8,然后大声告诉小红:p=23,g=5,A=8;

小红收到小明发来的p,g,A后,也选一个秘密整数b=15,然后计算B=g^b mod p=19,并大声告诉小明:B=19;

小明自己计算出s=B^a mod p=2,小红也自己计算出s=A^b mod p=2

,因此,最终协商的密钥s为2。

在这个过程中,密钥2并不是小明告诉小红的,也不是小红告诉小明的,而是双方协商计算出来的。第三方只能知道p=23,g=5,A=8,B=19,由于不知道双方选的秘密整数a=6和b=15,因此无法计算出密钥2。

用crypto模块实现DH算法如下:

constcrypto =require('crypto');// xiaoming's keys:varming = crypto.createDiffieHellman(512);varming_keys = ming.generateKeys();varprime = ming.getPrime();vargenerator = ming.getGenerator();console.log('Prime: ' prime.toString('hex'));console.log('Generator: ' generator.toString('hex'));// xiaohong's keys:varhong = crypto.createDiffieHellman(prime, generator);varhong_keys = hong.generateKeys();// exchange and generate secret:varming_secret = ming.computeSecret(hong_keys);varhong_secret = hong.computeSecret(ming_keys);// print secret:console.log('Secret of Xiao Ming: ' ming_secret.toString('hex'));console.log('Secret of Xiao Hong: ' hong_secret.toString('hex'));

运行后,可以得到如下输出:

$ node dh.js

Prime: a8224c...deead3

Generator: 02

Secret of Xiao Ming: 695308...d519be

Secret of Xiao Hong: 695308...d519be

注意每次输出都不一样,因为素数的选择是随机的

 

在Mac或Linux环境下,请打开终端,然后输入node -v,你应该看到如下输出:

方法2.var streamwriter = fs.createWriteStream(path);

因为Node.js是开源项目,虽然由社区推动,但幕后一直由Joyent公司资助。由于一群开发者对Joyent公司的策略不满,于2014年从Node.js项目fork出了io.js项目,决定单独发展,但两者实际上是兼容的。

写一个目录树显示的实现:

run-node-hello

}

更重要的是,如果我们要使用模块A,而模块A又依赖于模块B,模块B又依赖于模块X和模块Y,npm可以根据依赖关系,把所有依赖的包都下载下来并管理起来。否则,靠我们自己手动管理,肯定既麻烦又容易出错。

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 

'use strict';console.log('Hello, world.');

app.use(function(req,res){

推荐两款文本编辑器:

}else{

Node.js是目前非常火热的技术,但是它的诞生经历却很奇特。

var m4 =  $require('../xx.js');

上面的一大堆文字告诉你,npm需要跟上命令。现在我们不用关心这些命令,后面会一一讲到。目前,你只需要确保npm正确安装了,能运行就行。

//打印当前目录所有文件

使用模块有什么好处?

早期JS擅长处理字符串,及HTML文档,不会接触到二进制的数据。

直接可以看到结果600。

其他文件api

没有竞争就没有发展。微软认为IE6浏览器已经非常完善,几乎没有可改进之处,然后解散了IE6开发团队!而Google却认为支持现代Web应用的新一代浏览器才刚刚起步,尤其是浏览器负责运行JavaScript的引擎性能还可提升10倍。

 

C:Workspace>node hello.js

files.push(info);

第一行总是写上'use strict';

}

 

var begin = new Date().getTime();

res.writeHead(200,{'Content-Type':'text/plain'});

const dirname = path.dirname(filename);

 

假定有一个xxx.lrc文件

 

 

app.use("/home", function(request, response, next) {
  response.writeHead(200, { "Content-Type": "text/plain" });
  response.end("Welcome to the homepage!n");
});

app.use("/about", function(request, response, next) {
  response.writeHead(200, { "Content-Type": "text/plain" });
  response.end("Welcome to the about page!n");
});

app.use(function(request, response) {
  response.writeHead(404, { "Content-Type": "text/plain" });
  response.end("404 error!n");
});

http.createServer(app).listen(1337);

还可以这样写(*是指所有的请求都要先通过这个中间件)

app.all("*", function(request, response, next) {
  response.writeHead(200, { "Content-Type": "text/plain" });
  next();
});

app.get("/", function(request, response) {
  response.end("Welcome to the homepage!");
});

app.get("/about", function(request, response) {
  response.end("Welcome to the about page!");
});

app.get("*", function(request, response) {
  response.end("404!");
});

 

缓冲区:内存中操作数据的容器。

 

 

 

;`;

(参考

});

 

 

var dirinfo = fs.readdirSync(target);

 

清空require中的缓存机制:

console.log(module)

load(path.join(target,dir),depth 1);

而在Node中操作数据,网络通信是完全没法以字符串的方式操作的,所以在Node中引入了一个二进制缓冲区的实现,Buffer

}

 

 

(function($require,module,exports,__dirname,__filename){

res.end('404 Error!n');

util:提供一系列实用小工具。

 

console.log(`${prefix}${--count?'├':'└'}─${file}`);

files.forEach(file=>{

}else{

const fs = require('fs');

load(target,0);

var http = require("http");
var app = http.createServer(function(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.end("Hello world!");
});

app.listen(3000, "localhost");

var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('Hello world!');
});

app.listen(3000);

中间件(middleware)是处理HTTP请求的函数。

const path = require('path');

 

eval(code);

});

if(req.url == '/')

path:处理文件路径。

 

 

 

next();

方法2.用stream的方式读入 var streamReader = fs.createReadStream(filename);

0--node.exe的目录
1--js文件的目录
2--第一个参数

process.argv.slice(2) 获取从第一个参数开始的参数



2.process.env 获取当前系统的环境变量



3.process.stdout.write('xxx')

console.log('xxx') = process.stdout.write('xxxn');

4.process.stdin.on('data',function(data){

   process.stdout.write(data);
})
//回车时触发


传统的java,.net遇到阻塞io时会创建新的线程来处理。 node内部实现其实也是多线程的,(通过线程池)
//
多线程都是‘假’的,对于一个cpu核心。创建线程需要时间,线程数量有限,cpu在不同线程间切换需要转换上下文,耗费时间
多线程的意义并不大(多核心cpu则可能会提升效率)


node的主线程————事件队列与事件循环圈。

})($require,module,exports,dirname,filename)

if($require.cache[filename]){

 

};

app.use(function(req,res,next){

 

Object.keys(require.cache).forEach((key)=>{delete require.cache[key]});

return module.exports;

 

为什么要有缓冲区?

dirs.forEach(dir=>{

 

function load(target,depth){

 

xxx.js

module中有一个exports对象,可以向内添加属性和方法

{

$require.cache[filename] = module;

var data = '';

var files = [];

exports的实现:

....(打印出module对象)

 

querystring:解析URL中的查询字符串。

本文由分分快三计划发布,转载请注明来源

关键词: 分分快三计划 日记本 nodejs Node