异步I/O
异步I/O input/output
1.文件操作
2.网络操作
在浏览器中也存在异步操作:
1.定时任务
2.事件处理
3.Ajax回调处理
js的运行是单线程的
引入事件队列机制
Node.js中的事件模型与浏览器中的事件模型类似
单线程+事件队列(JS的运行是单线程的,但是Node.js的环境和浏览器的环境是多线程的)
Node.js中异步执行的任务:
1.文件I/O
2.网络I/O
Node.js是基于回调函数的编码风格
1.文件操作
const fs = require('fs'); //异步操作 //一般回调函数的第一个参数是错误对象,如果err为null,表示没有错误,否则表示报错了 //..表示上级目录,.表示当前目录 //异步的执行结果是:先输出1 再输出3 最后输出2 //因为第二个异步的任务会进入到事件队列中,当主线程代码都执行完了,才能空闲去事件队列中把任务取出来执行 console.log(1); fs.stat('../buffer',(err,stat) => { if(err) return; if(stat.isFile()){ console.log('文件'); }else if(stat.isDirectory()){ console.log('目录'); } console.log(stat); console.log(2); }); console.log(3);
//异步操作是没有返回值的,只有同步操作才有返回值 //同步操作 //执行顺序肯定是:1 ret 2 console.log(1); let ret = fs.statSync('./01.js'); console.log(ret); console.log(2);
/** * 读文件操作 */ const fs = require('fs'); const path = require('path'); //异步操作 let strpath = path.join(__dirname,'01.js'); //__dirname表示当前文件夹的绝对路径 //如果有第二个参数并且是编码,那么回调函数获取到的数据就是字符串 //如果没有第二个参数,那么得到的就是Buffer实例对象 fs.readFile(strpath,(err,data) => { if(err) return; console.log(data.toString()); //不调用toString(),则打印出来的是Buffer对象 }); //同步操作 let ret = fs.readFileSync(strpath,'utf8'); console.log(ret); /** * 写文件操作 */ //异步操作 //注意:写入的内容会覆盖掉文件里原来的内容 fs.writeFile(strpath,'hello world','utf8',(err) => { if(err) throw err; console.log('文件写入成功!'); }); let data = Buffer.from('hi'); fs.writeFile(strpath,data,'utf8',(err) => { if(err) throw err; console.log('文件写入成功!'); }); //同步操作 let ret = fs.writeFileSync(strpath,'tom and jerry','utf8'); console.log(ret); //返回undefined
/** * 大文件操作(流式操作) * fs.createReadStream(path[, options]) * fs.createWriteStream(path[, options]) */ const path = require('path'); const fs = require('fs'); let spath = path.join('E://','test.zip'); let dpath = path.join('E://','file.zip'); console.log(spath); let readStream = fs.createReadStream(spath); let writeStream = fs.createWriteStream(dpath); //console.log(writeStream); //基于事件的处理方式 let num = 1; readStream.on('data',(chunk) => { num++; writeStream.write(chunk); }); readStream.on('end',() => { console.log('文件处理完成'+num); }); //============================================================ //pipe的作用直接把输入流和输出流链接到一块 //readStream.pipe(writeStream); fs.createReadStream(spath).pipe(fs.createWriteStream(dpath));
2.目录操作
/** * 目录操作: * 1.创建目录 * fs.mkdir(path[, options], callback) * fs.mkdirSync(path[, options]) * 2.读取目录 * fs.readdir(path[, options], callback) * fs.readdirSync(path[, options]) * 3.删除目录 * fs.rmdir(path[, options], callback) * fs.rmdirSync(path[, options]) */ const path = require('path'); const fs = require('fs'); //创建目录 //异步操作 fs.mkdir(path.join(__dirname,'abc'),(err) => { console.log(err); //若没有错误,则返回null }); //同步操作 fs.mkdirSync(path.join(__dirname,'hello')); //读取目录 //let pathdir = path.join(__dirname,'../es6'); let pathdir = __dirname //异步操作 fs.readdir(pathdir,(err,files) => { if(err) return; files.forEach((item,index) => { fs.stat(path.join(pathdir,item),(err,stat) => { if(stat.isFile()){ console.log(item,'文件'); }else if(stat.isDirectory()){ console.log(item,'目录'); } }); }); }); //同步操作 let files = fs.readdirSync(pathdir); files.forEach((item) => { fs.stat(path.join(pathdir,item),(err,stat) => { if(stat.isFile()){ console.log(item,'文件'); }else if(stat.isDirectory()){ console.log(item,'目录'); } }); }); //删除目录 //异步操作 fs.rmdir(path.join(__dirname,'abc'),(err) => { console.log(err); }); //同步操作 let ret = fs.rmdirSync(path.join(__dirname,'hello')); console.log(ret);
3.初始化目录结构
/** * 文件操作案例(初始化目录结构) */ const path = require('path'); const fs = require('fs'); //创建的根目录的路径 let root = 'E:\\'; //用反引号 let fileContent = ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div>welcome!</div> </body> </html> `; //初始化数据 let initData = { projectName : 'mydemo', data :[{ name : 'img', type : 'dir' }, { name : 'css', type : 'dir' }, { name : 'js', type : 'dir' }, { name : 'index.html', type : 'file' }] }; //创建项目跟路径 fs.mkdir(path.join(root,initData.projectName),(err) => { if(err){ console.log('创建失败!'); return; } //创建子目录和文件 initData.data.forEach((item) => { if(item.type == 'dir'){ //创建子目录 fs.mkdirSync(path.join(root,initData.projectName,item.name)); }else if(item.type == 'file'){ //创建文件并写入内容:若没有这个文件,则自动创建然后写入内容 fs.writeFileSync(path.join(root,initData.projectName,item.name),fileContent); } }); });