node.js学习之路一(基础)

1.模块化的优点:低耦合 高内聚 方便维护 防止代码冲突(命名冲突)
2.nodejs实现模块化是用闭包。
3.CMD(seajs)--就近依赖 AMD(requirejs)--依赖前置 浏览器端的模块化
4.node基于规范commonjs 文件读写,node天生自带模块化
----1).定义如何创建一个模块 一个js文件你就是一个模块
----2).如何使用一个模块 require文件
----3).如何引用一个模块 exports 或者 moudle.exports

5.给exports对象赋值,可以直接导致module.exports对象的变化,如export.a = a,即会导出module.exports = a; 当然也可以直接改变module.exports的指向,两种方式最终导出的都是module.exports ,如下图
image.png
我们也能通过global拿到sum,
方法文件global.sum = sum,,,调用文件:global.sum(1,2,3,4)

6.require具有缓存功能,多次引用只执行一次
7.第三方模块,要通过npm安装 ---node pacakge manager
------全局安装 - g (只能在命令行中使用)默认的安装路径是node_modules(查看默认安装路径npm root -g)

image.png
常用的模块:http-server,帮我们起一个本地服务,npm install http-server,使用:在某个路径下http-server启动服务

------本地安装 没有-g参数,安装之前需要初始化文件,记录安装文件 npm init -y --->生成package.json ,目录不能有中文或特殊字符或大写 ===>本地安装又分两种:
一是开发依赖(开发时使用,上线还需要),npm install jQuery(老版要加--save,新版可不加)
二是项目依赖(开发时使用,线上不使用),npm install jquery --save-dev

7.发布包:先切换到国外:nrm use npm ;包名不能和已有的包一样; 入口文件(main),做整合用的; 注册账号:npm addUSer ,有账号就是登陆,没有就是注册,新用户需要校验邮箱; 最后发布:npm publish


8.核心模块(重点来了,放大点)

fs: (let fs = require('fs'),既有同步,又有异步方法,异步有callback)

读取:文件不许存在,不存在会报错。不能通过‘/’读取内容,‘/’表示根目录

1.读取的默认类型是buffer
-----fs.readFile('1.txt','utf8',function(){})异步读取文件(同步用fs.readFileSync('1.txt','utf8')),异步有回调函数,同步没有
2.异步调用,太多容易导致回调地狱 ----> 解决办法:promise resolve成功 reject失败
3.es7的async和await,node版本至少是7.9,,async后面只能跟promise,同时async必须和await同时出现
4.promise.all方法,promise.all[read(),add()].then(function(){}) 都成功调用then,只要有一个失败就掉失败
5.promise解决两个问题:一是毁掉地狱问题,二是合并异步返回结果,

写操作

1.读取都是buffer,写都是utf8,读取文件文件必须存在,写的时候不存在实惠自动创建,有内容会被覆盖,不能直接反对向,需要调用tostring方法。
2.fs.writeFile('1.txt', '南京',function(){}),同步用writeFileSync
3. 同步读写和异步读写函数封装

let fs = require("fs")
// 同步 拷贝
function copySync(source, target) {
    // writeFileSync
    let res = fs.readFileSync(source)
    fs.writeFileSync(target, res)
}
copySync('1.txt', '2.txt')

// 异步拷贝
function copy(source, target, callback) {
    fs.readFile(source, function(err, data) {
        if (err) {
            return callback(err)
        } else {
            fs.writeFile(target, data, function(err) {})
        }
    })
}
copy('1.txt', '3.txt', function(err) {
    console.log(err)
})

4.文件状态

let fs = require("fs")
fs.start('/', function(err, stats) {  ‘/’ 是根路径
  console.log(stats)
  // atime  访问时间
  // mtime 修改时间
  // ctime change时间(和mtime大一样,ctime范围更大)
  // barthtime 出生日期 
  if (err) {  // 文件不存在,不存在不能读取 }
  else {
      console.log(stats.isFile()); // 是不是文件
      console.log(stats.isDirctory()); // 是不是文件夹
  }
})

5. 创建目录,不能调剂创建,也就是没有aaa,就创建不了aaa/bbb

fs.mkdir('aaa', function(err) {
    console.log(err)
})
// 递归创建多层目录
function makep(url, callback) {
    // a/b/c/d,首先将字符串分成4部分,第一步创建a,第二部创建b...
    let urlArr = url.split('/')  //[a,b,c,d]
    let idx = 0
    function make(p){
        // 循环完了,把递归停掉,不然会一直循环
        if (urlArr.length < idx) return
        // 在创建前看是否存在,如果不存在创建,存在继续下一次创建
        fs.Stats.apply(p, function(err) {
            if (err) {
                // err是不存在,创建
                fs.mkdir(p, function(err) {
                    if (err) return console.log(err)
                    idx++
                    // 必须要将上一次创建的目录拼接上,不然递归出的结果就是a,b,c,d四个目录
                    make(urlArr.slice(0, idx+1).join('/'))
                })
            } else {
                // 如果存在,调到下一次创建
                idx++
                make(urlArr.slice(0, idx+1).join('/'))
            }
        })
    }
    make(urlArr[idx])
}
makep('a/b/c/d', function(err) {
    console.log('创建成功')
})

path模块

1.path.join,path.reslove方法(特别重要)

let path = require('path')
// 拼一个路径出来,path.join方法
console.log(path.join('./a', './b'))  // 结果:a/b
console.log(path.join(__dirname, './b')) //  __dirname当前文件的目录,并且是绝对路径,怎样能生成投绝对路径,结果:C:\Users\chao.wang\Desktop\NODE\ZFPX\b
console.log(path.join(__dirname, './b', '..')) // b变为绝对路径,在提到上一级, 结果:C:\Users\chao.wang\Desktop\NODE\ZFPX

// path.reslove方法 (解析一个绝对路径出来,就是你给他一个相对,他返回一个绝对给你)
console.log(path.resolve('./a', './b'))  // 结果:C:\Users\chao.wang\Desktop\NODE\ZFPX\a\b
// 可以看出:path.resolve('./a', './b') 和 path.join(__dirname, './b') 返回的结果相同,可相互替换

2.path.delimiter,环境变量分隔符(还是可能有用的,比如看是mac还是win环境还是Linux环境)

console.log(path.delimiter)
console.log(path.win32.delimiter)
console.log(path.posix.sep)

9.事件,上面fs和path其实就是流,流基于事件

* 事件的发布订阅
let EventEmitter = require('events')
let {inherits} = require('util')  // 实现继承

function Person() {

}
let boy = new Person()
inherits(Person, EventEmitter)  // 继承

boy.on('smile', function(parm) {  // on就是事件的订阅(绑定)
    console.log(parm)
    console.log('哈哈')
})
// 执行
boy.emit('smile', '这里是参数')  // 事件的发布(执行)
// 移除
boy.removeListener('smile')  // removeAllListener,移除所有事件

es6写EventEmitter

class EventEmitter {
    // 'smile':[eat, cry, shopping]
    constructor() {
        this._events = {}
    }
    on(eventName, callback) {
        // 判断是否有这个事件
        if (!this._events[eventName]) {
            // 有
            this._events[eventName] = [callback]
        } else {
            // 没有这个事件,放入
            this._events[eventName].push(callback)
        }
    }
    emit(eventName) {
        this._events[eventName].forEach(cb => cb())
    }
}
let e = new EventEmitter()
let haha = () =>{
    console.log('smile')
}
e.on('smile', haha)  // 绑定几次执行几次
e.emit('smile')

流的介绍(可读流和可写流)

1.可读流 (on('data'), on('err'), on('end'), resume, pause5个方法)

let fs = require('fs')
// 读文件必须存在,每次能读多少,默认64k。 读取默认是buffer
let rs = fs.createReadStream('1.txt')
// 需要监听事件(流失基于事件),数据到来的事件 rs.emit('data', 数据)
// 默认是非流动模式,监听事件后变为流动模式
let arr = []
rs.on('data',function(data) {
    arr.push (data)
    rs.pause() // 暂停,暂停的是on('data)的触发
    // 恢复触发 rs.resume()
    setTimeout(function(){
        rs.resume()
    },1000)
})

// 默认data事件是不停的触发,知道文件的数据被全部读出来,,所有有一个读取结束的方法
rs.on('end', function() {
    console.log('end')
    // 拿最终数据
    console.log(Buffer.concat(arr).toString())
})
// 报错
res.on('err', function(err){
    console.log(err)
})
// rs.pause()
// 暂停,暂停的是on('data)的触发
// 恢复触发 rs.resume()

1.可写流createWriteStream

let fs = require('fs')
// 可写流默认占用16k
let ws = fs.createWriteStream('./4.txt',{highWaterMark: 5})  // 新建了个文件4.txt
console.log(ws)
// 可写流的两个方法 write 和 end, 也是异步的,可接受回调函数
// 可写流写数据,必须是字符串类型或者buffer类型
ws.write('12', fn)  // 调用下就会往文件里写一下,调用3次,4.txt内容121212
console.log(ws.write('12', fn))  // false ---> 和设置的highWaterMark有关,及如果空间不够的前一步开始返回false
ws.write('12', fn) 
console.log(ws.write('12', fn))  //false
ws.write('12', fn) 
console.log(ws.write('12', fn))  //false 
// 结束调用end,调用end后,不能再用write,同时会把所有write中的内容以最快的速度写入文件
ws.end('结束', fn)  // end内容也会写入文件,
function fn() {
    console.log(1)
}
// drain事件,当读入的文件全部写入后,就恢复读取(如果end方法调用了,就不会执行了,end会让内容快速写入)
ws.on('drain', function() {
    console.log('处理完了')
})
关于流注意:

一个300k文件,一次读64k,就需要读6次,在读取的第一次就开始写,但写一次只能写入16k,所以暂停读取,但调用drain后再恢复读取,就是读64k等写完后再读取64k.....
写个方法

// 30b 读取4b 5次 读取一次就开始写,只能写1b
let fs = require('fs') 
function pipe(source, target) {
    let rs = fs.createReadStream(source, {highWaterMark: 4})
    let ws = fs.createWriteStream(target, {highWaterMark: 1})
    // 开启可读流
    rs.on('data', function(chunk) {
        // 如果可写流不能继续写入了,就暂停读取
        if (ws.write(chunk) === false) {
            rs.pause()
        }
    })
    // 当当前读入的内容都写入到了文件中,调用继续读取
    ws.on('drain', function() {
        console.log(`打印几次就读了几次`)
        rs.resume()
    })
    // 当读取完毕,强制将内存中未写入的内容写入到文件中,关闭文件
    rs.on('end', function() {
        ws.end()
    })
}  
pipe('4.txt', '5.txt')

换一种快捷写法

let fs = require('fs') 
function pipe(source, target) {
    let rs = fs.createReadStream(source, {highWaterMark: 4})
    let ws = fs.createWriteStream(target, {highWaterMark: 1})
    rs.pipe(ws)  // 可读流.pipe(可写流),会自动调用write和end方法
}  
pipe('4.txt', '5.txt')
注:通过流可以实现分段,但是不关心文件中的内容,readFile可以看到文件中的具体内容(读一个很大的文件采用流)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容