node.js入门

node.js是什么
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。
Node.js 的包管理器 npm,是全球最大的开源库生态系统。

I/O
阻塞:I/O时进程休眠等到I/O完成后进行下一步
非阻塞:I/O时函数立即返回,进程不等待I/O完成

事件驱动
I/O等异步操作完成后的通知

cpu密集:解压 压缩 加密 解密
I/O密集:文件操作 、网络操作、数据库

node也是单线程
单线程针对的是主进程 I/O操作系统底层多进程调度
单线程不是单进程 例如八核cpu 启动八个进程

常用场景
web server
本地代码构建
实用工具开发

//node 和java?

环境
CommonJs每个文件是一个模块,有自己的作用域
模块内部module变量代表模块本身
module.export代表模块对外的接口

全剧对象是global
控制台中使用 node xx.js来执行

require规则
/表示绝对路径 ./表示相当于当前文件的相对路径
支持js json node拓展名
不写路径则认为是build-in模块或各级node_modules内的第三方模块

require特性
1.module被加载的时候执行,加载后缓存
2.出现某个模块被循环加载 (例如两个模块相互引用),就只输出已被执行部分,(实际上尽量避免这么写)

例子 写两个js文件

cusmod.js

console.log('this is a module');

const testVar  = 100;
function test() {
    console.log(testVar);
}

module.exports.testVar = testVar;
module.exports.testFn = test;

require.js

const mod = require('./02_cusmod');

console.log(mod.testVar);

mod.testFn();

在git中使用node 文件名的方式就可以看到结果

结果看到
this is a module
100
100
全部打印出来了而不是只执行了test 所以要写在function中,只暴露想让用户调用的方法

缓存的特性可以通过引入两个相同的模块 只打印一次结果可以看出

2.一旦出现某个模块循环加载,只输出已经执行的部分,还未执行的部分不会输出;

05_main.js

const modeA = require('./05_modeA');
const modeB = require('./05_modeB');

05_modeA.js

module.exports.test = 'A';//部分加载完 输出'A’

const modeB = require('./05_modeB');

console.log('modeA', modeB.test);

module.exports.test = 'AA';//全部加载完 输出的应该是AA

05_modeB.js

module.exports.test = 'B';

const modeA = require('./05_modeA');

console.log('modeB', modeA.test);

module.exports.test = 'BB';

执行过程 先到a模块中 test被赋值为A 然后A模块依赖于模块B 于是到了B模块 发模块B的test先被赋值为B然后发现B又依赖A,于是根据第一条加载完缓存,和第二条规则只输出已经执行的部分 ,所以B中打印test的结果为A,然后B执行完毕,test被赋值为BB,所以模块A中的test打印结果为BB,main中的requireA部分执行完毕,到requireB的时候发现已经缓存了B模块,所以不会重复执行

module.exports 和 exports的关系

module.expors的简写是exports 可以给他添加属性 ,但是不能修改他的指向

// exports.test =  100;//成功打印

// exports = {
//     a : 1,
//     b : 2,
//     test: 100
// };//undefined
module.exports = {
    a : 1,
    b : 2,
    test: 100
};//100



global
08_main

// const exps = require('./08_exps');
// console.log(exps.test);

const mod = require('./08_global');
console.log(mod.testVar);//1000
//console.log(testVar);//报错
console.log(testVar2);//200 挂载到global的全局变量



08_global

const testVar = 1000;
global.testVar2 = 200;//会变成全局变量
module.exports.testVar = testVar;


process

//porcess的子对象
const {argv, argv0, execArgv, execPath} = process;
argv.forEach(item => {
    console.log(item);
    /*C:\Program Files\nodejs\node.exe 保存node安装的目录
    C:\Users\admin\Desktop\H5\node.js\入门\nodetest\commonJS\10_argv.js 当前执行文件的路径
*/
})

console.log(argv0)//node  保存argv的第一个值 不常用

console.log(execArgv)//调用node传入的一些特殊参数
//node --inspect 10_argv.js --test  --inspect相当于传入的参数 在最后面打印
/*
C:\Program Files\nodejs\node.exe
C:\Users\admin\Desktop\H5\node.js\入门\nodetest\commonJS\10_argv.js
--test
node
    [ '--inspect' ]
*/


console.log(execPath);//C:\Program Files\nodejs\node.exe  


关于调试
在chrome中可以打开chrome://inspect这个地址 安装一个chrome的插件
详情参考 https://nodejs.org/en/docs/inspector/

webstorm调试node的方法 http://www.cnblogs.com/jinguangguo/p/4809886.html
断点调试的方法 http://blog.youkuaiyun.com/u011277123/article/details/58585259

基础api

path:
normalize 把路径进行简单处理 处理一些小问题 改成标准的路径格式
// -> /
… ->删除

const {normalize} = require('path');
//const normalize = require('path').normalize;等于上一句 上面是es6写法
console.log(normalize('/usr//local/bin'));//\usr\local\bin
console.log(normalize('/usr//local/../bin'));//\usr\bin

join 拼接路径 不用手动处理/的问题

const {join} = require('path');

console.log(join('/usr', 'lcoal', 'haha/'))//\usr\lcoal\haha\

resolve 将相对路径解析成绝对路径

const {resolve} = require('path');

console.log(resolve('./'));//查看当前路径的绝对路径

names

const {basename, dirname, extname} = require('path');
const  filepath =  '/usr/loacal/bin/no.txt';

console.log(basename(filepath));//文件名no.txt
console.log(dirname(filepath));//所在文件夹/usr/loacal/bin
console.log(extname(filepath));//拓展名.txt


parse format

const {parse, format} = require('path');

const  filepath =  '/usr/loacal/node_modules/n/package.json';

const  ret = parse(filepath);
console.log(ret)//分析一个路径

console.log(format(ret));//将解析的结果变回原来的路径

parse的解析结果如下
{ root: ‘/’,
dir: ‘/usr/loacal/node_modules/n’,
base: ‘package.json’,
ext: ‘.json’,
name: ‘package’ }

用处在于想修改路径中的某一项 先parse修改后再format回去

总结 _dirname _filename总是返回文件的绝对路径
process.cwd()总是返回执行node命令的文件夹
./在require方法中总是相对于当前文件所在的文件夹

Buffer
1.解决二进制的问题 2.实例类似整数数组,大小固定 是一个全局变量 可以直接使用

console.log(Buffer.alloc(10));//默认用0填充的长度是10
console.log(Buffer.alloc(10,1));//用1填充
console.log(Buffer.allocUnsafe(5,1));//内容随机
console.log(Buffer.from([1,2,3]));//以数组内容填充
console.log(Buffer.from('test'));//以字符串填充  每个编码代表一个字母 默认utf-8编码



//实际占了几个字节
console.log(Buffer.byteLength('test'));//4
console.log(Buffer.byteLength('测试'));//6

//是否为buffer对象
console.log(Buffer.isBuffer({}));//false
console.log(Buffer.isBuffer(Buffer.from([1,2,3])));//true

//拼接
const buffer1 =  Buffer.from('this');
const buffer2 =  Buffer.from(' is');
const buffer3 =  Buffer.from(' a');
const buffer4 =  Buffer.from(' test');
const buffer5 =  Buffer.from('!');
const buf = Buffer.concat([buffer1, buffer2, buffer3, buffer4, buffer5]);
console.log(buf.toString());
//解决中文乱码问题
const StringDecoder = require('string_decoder').StringDecoder;
const decoder = new StringDecoder('utf8');
const buf = Buffer.from('中文字符串');

for(let i = 0; i < buf.length; i+=5){
    const b = Buffer.allocUnsafe(5);
    buf.copy(b, 0 ,i);

    console.log(b.toString());//三个字符表示一个中文字 这里用五个拆 必然是乱码
}

for(let i = 0; i < buf.length; i+=5){
    const b = Buffer.allocUnsafe(5);
    buf.copy(b, 0 ,i);

    console.log(decoder.write(b));
}

events
大多数的node的api都采用异步事件驱动,其中的某些触发器会周期的触发命名事件来调用函数对象(监听器);

const EventEmitter = require('events');

class CustomEvent extends EventEmitter {


}

const  ce = new CustomEvent();
ce.on('test', () => {
    console.log('this is a test!');
})
setInterval(() => {
    ce.emit('test');
}, 500);

每隔500ms会打印一次

可以传参数

const EventEmitter = require('events');

class CustomEvent extends EventEmitter{

}

const ce = new CustomEvent();

ce.on('error', (err, time) => {
    console.log(err);
    console.log(time);
});

ce.emit('error', new Error('oops!'), Date.now())

响应一次

const EventEmitter = require('events');

class CustomEvent extends EventEmitter{

}

const  ce = new CustomEvent();
//只响应一次
ce.once('test', () => {
    console.log('this is a test!');
})
setInterval(() => {
    ce.emit('test');
}, 500);

移除绑定

const EventEmitter = require('events');

class CustomEvent extends EventEmitter{

}

function fn1() {
    console.log('fn1');
}
function fn2() {
    console.log('fn2');
}
const  ce = new CustomEvent();


ce.on('test',fn1);
ce.on('test',fn2);
setInterval(() => {
    ce.emit('test');
}, 500);


setTimeout(() => {
    //移除掉fn2
    ce.removeListener('test', fn2)

    //全部都移除掉
    ce.removeAllListeners('test')
},1500);



fs
文件系统file system
所有方法都有同步和异步两种方式 推荐用异步
异步方法最后一个参数都是一个回调函数 但回调函数的第一个参数一定是留个异常的 如果操作成功完成 第一个参数为null或者undefined

读文件

const fs = require('fs');

fs.readFile('./32_readfile.js','utf8', (err, data) => {
    if (err) throw err;

    console.log(data)
})
//这是同步操作


const data = fs.readFileSync('./02_cusmod.js', 'utf8');
console.log(data);

写文件

const fs = require('fs');

fs.writeFile('./text','this is a test', {
    encoding : 'utf8'
}, err => {
    if (err) throw err;
    console.log('done !');
})

文件信息

const fs = require('fs');

fs.stat('./34_stat.js', (err, stats) => {
    if (err) throw err;
    console.log(stats.isFile());//是不是文件
    console.log(stats.isDirectory());//是不是文件夹
    console.log(stats);
})

重命名

const fs = require('fs');

fs.rename('./text', 'test,txt',err => {
    if (err) throw err;
    
    console.log('done')
})

删除

const fs = require('fs');

fs.unlink('./test.txt',err => {
    if (err) throw err;

    console.log('done')
})

读文件夹

const fs = require('fs');

fs.readdir('./', (err, files) => {
    if (err) throw err;

    console.log(files)
})

创建文件夹

const fs = require('fs');

fs.mkdir('test', err => {
    if (err) throw err;

    console.log(files)
})

删除文件夹

const fs = require('fs');

fs.rmdir('test', err => {
    if (err) throw err;

    console.log(files)
})

监视文件

const fs = require('fs');
//常用 和watchfile差不多  watch能监视任何内容 watchfile只能监视文件
fs.watch('./', {
    recursive: true //子文件夹也监视
}, (eventType, filename) => {
    console.log(eventType, filename)
})//修改会提示change xxx 删除创建文件提示 rename xxx
eventType判断文件是被删除还是修改


举个例子 1L的水桶接5L水,一边接一边用勺子舀
又例如网页 加载一点 显示一点

//一个数据流向另外一个

//数据 流向

const fs = require('fs');
const rs = fs.createReadStream('./41_readsteam.js'); // 创建流 流的内容就是这个文件

rs.pipe(process.stdout)//stdout就是命令台那里显示 流的方向
//一个数据流向另外一个

//数据 流向

const fs = require('fs');
const ws = fs.createWriteStream('./test2.txt');

const tid = setInterval(() => {
    const num = parseInt(Math.random() * 10);
    console.log(num)
    if (num < 8){
        ws.write(num + '')//接受的字符串或者buffer
    }else {
        clearInterval(tid);
        ws.end();
    }

},200)//模拟写一部分数据

ws.on('finish', () => {
    console.log('done')
})

解决回调地狱

//回调地狱 一个异步里调用另外一个异步。。。

const fs = require('fs');
const promisify = require('util').promisify;

const read = promisify(fs.readFile);

//解决回调地狱方法一
// read('./43_promisify').then(data => {
//     console.log(data.toString());
// }).catch(ex => {
//     console.log(ex);
// })

//方法二 
async  function test() {
    try{
        const content = await read('./43_promisify.js');
        console.log(content.toString())
    }catch (ex){
        console.log(ex)
    }

}

test();

学做一个静态资源服务器

.gitignore
上传的时候忽略上传哪种文件 例如node_modules

复制自己的github地址. 在命令行中 git clone加仓库地址

gitignore的规则
匹配模式前/代表根目录
匹配模式后/代表目录
匹配模式加!表示不忽略这个文件 (忽略一个文件夹 但是不想忽略其中某些文件不想忽略 就用!)
*代表任意字符
?表示一个字符
**匹配多级目录
# 代表注释

readme
采用的markdown语法

editconfig
http://editorconfig.org/
按项目确定代码风格
root = true 不要往上找了 这就是根目录

end_of_line = lf 用unix风格还是windows风格的回车 lf表示unix

[*.{js,py}]
charset = utf-8 js或者py文件用utf8的字符集

[*.py]
indent_style = space 缩进是用space
indent_size = 4 //4个空格

# EditorConfig is awesome: http://EditorConfig.org

# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true

# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,py}]
charset = utf-8

# 4 space indentation
[*.py]
indent_style = space
indent_size = 4

# Tab indentation (no size specified)
[Makefile]
indent_style = tab

# Indentation override for all JS under lib directory
[lib/**.js]
indent_style = space
indent_size = 2

# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2

gulp的使用
node_modules中bin文件夹代表安装的包暴露出的可执行的
均为gulpfile文件下
给文件搬家
这里写图片描述

gulp-less把less转为css
[ ]中的内容表示 依赖 也就是先执行less任务再执行default

这里写图片描述
有个问题 这里会保留之前的less文件 怎么清除呢?
第一种方法在配置中改
第二种在代码中 引入del
这里写图片描述

写样式的时候加浏览器前缀很麻烦 用gulp-aotuprefixer
can i use 网站可以查找哪些样式需要加前缀
这里写图片描述

压缩css gulp-clean-css

这里写图片描述

watch
这里写图片描述

在配置这添加watch
这里写图片描述

babel处理js
babel-preset-env 针对es2015后的语法
创建.babelrc
这里写图片描述
有个问题 如果出现es2015之前的语法 怎么办
需要安装单独的插件
例如object.assign
http://babeljs.io/docs/plugins/

webpack
配置文件为webpack.config.js
entry和output入口和出口文件

怎么解决react或者像less的问题呢 使用webpack-loader 和less-loader

这里写图片描述

参考https://doc.webpack-china.org/concepts/

爬虫
反爬虫
通过user-agent如果看到是爬虫就拒绝访问
通过验证码
单位时间的访问量和访问次数 监测
关键信息用图片混淆
异步加载

node中的cheerio爬虫有缺陷绕不过反爬虫

我们使用puppeteer 适用chrome
参考https://www.npmjs.com/package/puppeteer

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值