Node.js

作者: 彼得朱 | 来源:发表于2019-07-07 14:46 被阅读0次

1、终端基本使用

打开应用

  • notepad 打开记事本
  • mspaint 打开画图
  • calc 打开计算机
  • write 写字板
  • sysdm.cpl 打开环境变量设置窗口

常用命令

  • md 创建目录
  • rmdir(rd) 删除目录,目录内没有文档。
  • echo on > a.txt 创建空文件
  • echo 内容 > a.txt 往文件里写内容
  • echo 内容 >> a.txt 往文件里追加内容,同时也会覆盖以前的
  • del 删除文件
  • rm 文件名 删除文件
  • cat 文件名 查看文件内容
  • cat > 文件名 向文件中写上内容

2、Node.js开发环境搭建

  • Node.js 介绍
    • Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境
    • Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效
    • Node.js 的包管理器 npm,是全球最大的开源库生态系统
    • javascript 是脚本语言,需要解析器才能执行,浏览器就充当了解析器
    • 在Chrome中,解析器就是 V8 引擎,将 javascript 转换成 机器码
    • V8 引擎是开源的,由 C++ 语言编写,性能高
    • Node.js 高性能,事件驱动,非阻塞,生态圈很好
  • Node.js 普通安装
    • 官网 下载安装即可,很小不到20M!
    • 验证是否成功,命令行输入 node -v 显示版本号如 v8.11.4
    • 按提示升级 npm,Update available 5.6.0 → 6.4.1, npm i -g npm
  • Node.js多版本安装方式
    • 卸载已有的Node.js
    • 下载nvm
    • 在C盘创建目录dev
    • 在dev目中中创建两个子目录nvm和nodejs
    • 并且把nvm包解压进去nvm目录中
    • 在install.cmd文件上面右键选择【以管理员身份运行】
    • 打开的cmd窗口直接回车会生成一个settings.txt文件,修改文件中配置信息
    • 配置nvm和Node.js环境变量
      • NVM_HOME:C:\dev\nvm
      • NVM_SYMLINK:C:\dev\nodejs
    • 把配置好的两个环境变量加到Path中
  • nvm常用的命令
    • nvm list 查看当前安装的Node.js所有版本
    • nvm install 版本号 安装指定版本的Node.js
    • nvm uninstall 版本号 卸载指定版本的Node.js
    • nvm use 版本号 选择指定版本的Node.js

3、全局对象

  • 全局对象

    • 不用导入,直接使用的对象
    • 官方文档
    • Buffer 类,用于处理二进制数据
    • console,用于打印 stdout 和 stderr
    • global, 全局的命名空间对象
    • process,进程对象
    • setTimeout(callback, delay[, ...args])
    • setInterval(callback, delay[, ...args])
    • setImmediate(callback[, ...args])
    • clearTimeout(timeoutObject)
    • clearInterval(intervalObject)
    • clearImmediate(immediateObject)
  • 以下变量虽然看起来像全局变量,但实际上不是

    • 全局变量在所有模块中均可使用
    • 以下对象作用域只在模块内,详见 module文档
    • __dirname
    • __filename
    • exports
    • module
    • require()
  • 运行 .js 脚本文件

    • node app 或者 node app.js
  • 实践代码

    console.log('hello world');
    
    setTimeout(function () {
        console.log("3 seconds have passed 2");
    }, 3000);
    
    // 箭头函数,es6的写法
    setTimeout(() => {
        console.log("3 seconds have passed 1");
    }, 3000);
    
    // 每间隔2秒不断执行
    setInterval(function () {
        console.log("2 seconds have passed");
    }, 2000);
    
    
    var time = 0
    var timer = setInterval(function () {
        time += 2;
        console.log(time + " seconds have passed");
        if (time > 6) {
            clearInterval(timer);
            console.log("clearInterval")
        }
    }, 2000)
    
    // 输出当前目录 和 带绝对路径的文件名
    console.log(__dirname)
    console.log(__filename)
    
    console.log('end')
    console.dir(global)
    

4、回调函数

function sayHi() {
    console.log('Hi')
}

sayHi() // 调用函数

// 将匿名函数赋给变量
var sayBye = function (name) {
    console.log(name + ' Bye')
}

sayBye()

// 第一个参数是函数
function callFunction(fun, name) {
    fun(name)
}

callFunction(sayBye, 'able')
// 或者
callFunction(function (name) {
    console.log(name + ' Bye')
}, 'able')

5、模块化

传统非模块化开发有如下的缺点:

​ 1、命名冲突

​ 2、文件依赖

前端标准的模块化规范:

​ 1、AMD - requirejs

​ 2、CMD - seajs //阿里的

服务器端的模块化规范:

​ 1、CommonJS - Node.js

模块化相关的规则:

​ 1、如何定义模块:一个js文件就是一个模块,模块内部的成员都是相互独立

​ 2、模块成员的导出和引入

​ 模块成员的导出最终以module.exports为准

​ 如果要导出单个的成员或者比较少的成员,一般我们使用exports导出;

​ 如果要导出的成员比较多,一般我们使用module.exports的方式

​ 这两种方式不能同时使用

​ exports与module的关系:

​ module.exports = exports = {};

module 对象

  • 每个文件都被视为独立的模块
  • 每个模块中,module 指向表示当前模块的对象的引用
  • module 实际上不是全局的,而是每个模块本地的
  • module.exports 导出模块内的对象,方便其他对象引用
  • require() 引入模块
  • 当 Node.js 直接运行一个文件时,require.main 会被设为它的 module
  • 可以通过 require.main === module 来判断一个文件是否被直接运行
  • module 提供了一个 filename 属性(通常等同于 __filename)
  • 可以通过检查 require.main.filename 来获取当前应用程序的入口点
//例1
//导出 03.js
var sum = function(a,b){
    return parseInt(a) + parseInt(b);
}
exports.sum = sum;
//引入
var module = require('./03.js');

var ret = module.sum(12,13);
console.log(ret);    //输出  25
//例2
//导出 03.js
var sum = function(a,b){
    return parseInt(a) + parseInt(b);
}
module.exports = sum;
// 引入
var module = require('./03.js');
var ret = module(12,13);
console.log(ret);   //输出  25
//例3
//导出
var flag = 123;
global.flag = flag;  

//引入
require('./07');
console.log(global.flag);   //输出 123
//例4
var counter = function(arr){
    return "There are" + arr.length +"element in the array";
}

var adder = function(a,b){
    return `the sum of the 2 numnber is ${a+b}`;
}

var pi = 3.14;

// module.exports.counter = counter;
// module.exports.adder = adder;
// module.exports.pi = pi;
// 或者
module.exports = {
    counter: counter,
    adder:adder,
    pi:pi
}

//引入
var stuff = require('./9');

console.log(stuff.counter(['1','2','3'])); //输出 There are3element in the array
console.log(stuff.adder(5,5));   //输出 the sum of the 2 numnber is 10
console.log(stuff.pi);  // 输出 3.14

注意:已经加载的模块会缓存。

​ 模块文件的后缀3种情况:.js .json .node

​ 上述三种模块的加载优先级(不加文件后缀时的优先级):.js -> .json -> .node

6、buffer基本操作

Buffer对象是Node处理二进制数据的一个接口。它是Node原生提供的全局对象,可以直接使用,不需要require(‘buffer’)。

  • 实例化
    • Buffer.from(array)
    • Buffer.from(string)
    • Buffer.alloc(size)
  • 功能方法
    • Buffer.isEncoding() 判断是否支持该编码
    • Buffer.isBuffer() 判断是否为Buffer
    • Buffer.byteLength() 返回指定编码的字节长度,默认utf8
    • Buffer.concat() 将一组Buffer对象合并为一个Buffer对象
  • 实例方法
    • write() 向buffer对象中写入内容
    • slice() 截取新的buffer对象
    • toString() 把buf对象转成字符串
    • toJson() 把buf对象转成json形式的字符串

7、事件(events)

  • 多数 Node.js 核心 API 都采用异步事件驱动架构
  • 所有能触发事件的对象都是 EventEmitter 类的实例
  • 事件名称通常是驼峰式的字符串
  • 实践代码
//例1    
// 导入事件库
var events = require('events');

// 新建事件对象
var myEmitter = new events.EventEmitter();

// 绑定事件,事件名称叫做someEvent,后面是事件触发的回调函数
myEmitter.on('someEvent',function(message){
    console.log(message);
})
// 手动触发
myEmitter.emit('someEvent','the event was emmitted');  //the event was emmitted
//例2   (给对象一个事件)
var events = require('events');// 导入事件库
var util = require('util');    // 导入工具库

var Person = function(name){ //定义一个对象
    this.name = name;
}
// inherits是继承的意思,让Person类继承事件对象的属性
util.inherits(Person,events.EventEmitter);

// 定义三个对象
var xiaoming = new Person('xiaoming');
var lili = new Person('lili');
var lucy = new Person('lucy');

var persons = [xiaoming,lili,lucy];

// 循环数组,每个对象都绑定一个事件
persons.forEach(function(persons){
    persons.on('speak',function(message){
        console.log(persons.name +' said  '+ message);
    })
})
// 触发
xiaoming.emit('speak','hi');
lili.emit('speak','i want a apple');

// 注意,要让对象使用事件,就让对象继承那个事件库的对象就行了,也就是
// events.EventEmitter

8、读写文件(同步和异步)

//例1
var fs = require('fs');   //文件的一个库

var readMe = fs.readFileSync("readMe.txt","utf8");  //参数:文件名,编码
console.log(readMe);  // you read me!

fs.writeFileSync("writeMe.txt","这是写入的");  //参数:文件名,写入的东西
// 以上部分是同步执行情况
// node.js执行JavaScript的时候是单线程的,如果读写文件很耗时,他就会阻塞

注意:IO操作是很耗时的,它不能阻塞主线程,应该发起一个新的线程去执行它

​ noejs中异步处理操作,异步的操作都要加回调函数

//例2
// 解决办法,用异步
var fs = require('fs');

var readMe = fs.readFile("readMe.txt","utf8",function(err,data){
    console.log(data);     //you read me!
    fs.writeFile("writeMe.txt","写入的内容",function(){
        console.log('writeMe has finished!');
    })
})

console.log("finished");    //这个比上面那句先执行
// why
/*
    第二条语句是一个异步的事件,异步的IO操作,nodejs在执行JavaScript的时候
    是单线程的,语句还是一行一行往下执行,为什么这里会先执行最后一句呢?这是因为
    nodejs维护了一个事件队列,执行第二句的时候,会在事件队列那里注册一个事件,告诉
    这个事件队列我将要去读一个文件,但是这个回调函数没有被马上执行,这个操作是
    瞬间完成的。完成之后他就会执行主线程的第三个语句。当主线程空闲之后,它就会
    去找事件队列里面的事件,把它取出来,然后发起一个线程执行,执行成功后,它就
    告诉主线程我已经成功了,你来执行我吧。所以这里先执行的是主线程,然后执行的
    是异步操作里面的回调函数。

    注意:IO操作是很耗时的,它不能阻塞主线程,应该发起一个新的线程去执行它
          noejs中异步处理操作,异步的操作都要加回调函数
*/
 
//例3
var fs = require('fs');
// 异步删除文件
fs.unlink("writeMe.txt", function () {
    console.log("delete writeMe.txt file");
})

// 同步创建和删除目录
fs.mkdirSync('stuff');
fs.rmdirSync('stuff');

// 异步创建目录,但是这种递归回调,嵌套太多会出现问题,以后再说解决办法
fs.mkdir('stuff', function () {
    fs.readFile('readMe.txt','utf8',function(err,data){
        fs.writeFile('./stuff/writeMe.txt',data,function(){
            console.log('copy successfully');
        })
    })
});

9、流和管道

  • 流(stream)
    • 处理流式数据的抽象接口
    • stream 模块提供了一些基础的 API,用于构建实现了流接口的对象
    • 流可以是可读的、可写的、或是可读写的,所有的流都是 EventEmitter 的实例
    • 处理数据通过缓存可以提高性能
  • 管道
    • 使用管道,代码量更少
    • myReadStream.pipe(myWriteStream)
//例1
var fs = require('fs');
// 创建一个输入流
var myReadStream = fs.createReadStream(__dirname+'/readMe.txt');
// 流是一个事件的实例,拥有事件的一些特性,它可以绑定一些监听函数
myReadStream.on('data',function(chunk){
    console.log('new chunk received');  //new chunk received
    console.log(chunk);    //<Buffer 79 6f 75 20 72 65 61 64 20 6d 65 21>
})
// 性能提高的原因是文件分成buffer了
//例2
var fs = require('fs');
// 创建一个读的流
var myReadStream = fs.createReadStream(__dirname+'/readMe.txt');
//创建一个写入的流
var myWriteStream = fs.createWriteStream(__dirname+'/writeMe.txt');

//设置编码
myReadStream.setEncoding('utf8');

var data = ""
// 接收数据时用的监听函数
myReadStream.on('data',function(chunk){
    data += chunk;
    myWriteStream.write(chunk);//这里写入内容
})
//接受完数据之后用的
myReadStream.on('end',function(){
    console.log(data);
})
//例3
var fs = require('fs');
// 创建一个读的流
var myReadStream = fs.createReadStream(__dirname+'/readMe.txt');
//创建一个写入的流
var myWriteStream = fs.createWriteStream(__dirname+'/writeMe.txt');

var writeData = "hello world";

myWriteStream.write(writeData,'utf8');   //向文件中写入 "hello world"  
myWriteStream.end();
myWriteStream.on('finish',function(){
    console.log('finished');
})

以上三例是用流来写入或读出文件

//管道

var fs = require('fs');
// 创建一个读的流
var myReadStream = fs.createReadStream(__dirname+'/readMe.txt');
//创建一个写入的流
var myWriteStream = fs.createWriteStream(__dirname+'/writeMe.txt');

// 直接将 myReadStream内容 写入 myWriteStream
myReadStream.pipe(myWriteStream);
var crypto = require('crypto');  //加密
var fs = require('fs');
var zlib = require('zlib');   //压缩

var password = new Buffer(process.env.PASS || 'password');
var encryptStream = crypto.createCipher('aes-256-cbc',password);

var gzip = zlib.createGzip();
var readStream = fs.createReadStream(__dirname+"/readMe.txt");
var writeStream = fs.createWriteStream(__dirname+"/out.gz");

// 压缩
readStream
    .pipe(encryptStream)
    .pipe(gzip)
    .pipe(writeStream)
    .on('finish',function(){
        console.log('done');
    });
//解压缩
var crypto = require('crypto');  //加密
var fs = require('fs');
var zlib = require('zlib');   //解压缩

var password = new Buffer(process.env.PASS || 'password');
var decryptStream = crypto.createDeCipher('aes-256-cbc',password);

var gzip = zlib.createGunzip();
var readStream = fs.createReadStream(__dirname+"/out.gz");

// 解压缩
readStream
    .pipe(gzip)
    .pipe(decryptStream)
    .pipe(process.stdout)
    .on('finish',function(){
        console.log('done');
    });

10、http模块,web服务器

下面几个是响应一个纯文本给客户端

var http = require('http');

var server = http.createServer(function(request,response){
    console.log("Request received");
    response.writeHead(200,{'Content-Type':'text/plain'});
    response.write('Hello from out application');
    response.end();
})

server.listen(3000);
console.log('Server started on locahost port 3000');
1.png
2.png
//把上面的  server.listen(3000);改成下面这句
server.listen(3000,'127.0.0.1');
3.png
//改用 request 表达式
var http = require('http');

// request表达式
var onRequest = function(request,response){
    console.log("Request received");
    response.writeHead(200,{'Content-Type':'text/plain'});
    response.end('Hello from out application');
}

var server = http.createServer(onRequest);

server.listen(3000,'127.0.0.1');
console.log('Server started on locahost port 3000');

11、web服务器响应json

var http = require('http');

// request表达式
var onRequest = function(request,response){
    console.log("Request received");
    // 这里改为响应json的
    response.writeHead(200,{'Content-Type':'application/json'});
    var myObj = {
        name:'hfisdwc',
        job:'programmer',
        age:27
    }
    response.end(JSON.stringify(myObj));  //将对象转换成json字符串,写入response中
}

var server = http.createServer(onRequest);

server.listen(3000,'127.0.0.1');
console.log('Server started on locahost port 3000');
4.png

序列化:把它转成字符串 stringify

反序列化:把字符串转成对象 parse

  • JSON对象
    • 字符串必须使用双引号表示,不能使用单引号
    • 对象的键名必须放在双引号里面
    • 数组或对象最后一个成员的后面,不能加逗号
    • JSON对象是 JavaScript 的原生对象,用来处理 JSON 格式数据
    • JSON.stringify方法用于将一个值转为 JSON 字符串
    • JSON.parse方法用于将 JSON 字符串转换成对应的值

12、web服务器响应HTML

var http = require('http');
var fs = require('fs');

// request表达式
var onRequest = function(request,response){
    console.log("Request received");
    // 这里改为响应html的
    response.writeHead(200,{'Content-Type':'text/html'});
    var myReadStream = fs.createReadStream(__dirname+'/index.html','utf8');
    myReadStream.pipe(response);
}

var server = http.createServer(onRequest);

server.listen(3000,'127.0.0.1');
console.log('Server started on locahost port 3000');

13、模块化思想组织代码

var http = require('http');
var fs = require('fs');

function startServer() {
    // request表达式
    var onRequest = function (request, response) {
        console.log("Request received");
        // 这里改为响应html的
        response.writeHead(200, {
            'Content-Type': 'text/html'
        });
        var myReadStream = fs.createReadStream(__dirname + '/index.html', 'utf8');
        myReadStream.pipe(response);
    }

    var server = http.createServer(onRequest);

    server.listen(3000, '127.0.0.1');
    console.log('Server started on locahost port 3000');
}

// 导出
exports.startServer = startServer;
//导入
var server = require('./server');
server.startServer();

14、web服务器路由

var http = require('http');
var fs = require('fs');

function startServer() {
    var onRequest = function (req, res) {
        console.log('request received ' + req.url)

        if (req.url === '/' || req.url === '/home') {
            res.writeHead(200, { 'Content-Type': 'text/html' })
            fs.createReadStream(__dirname + '/index.html', 'utf8').pipe(res)
        } else if (req.url === '/review') {
            res.writeHead(200, { 'Content-Type': 'text/html' })
            fs.createReadStream(__dirname + '/review.html', 'utf8').pipe(res)
        } else if (req.url === '/api/v1/records') {
            res.writeHead(200, { 'Content-Type': 'application/json' })
            var jsonObj = {
                name: 'able'
            }
            res.end(JSON.stringify(jsonObj))
        } else {
            res.writeHead(200, { 'Content-Type': 'text/html' })
            fs.createReadStream(__dirname + '/404.html', 'utf8').pipe(res)
        }
    }
    var server = http.createServer(onRequest)
    server.listen(3000)
    console.log('server started on http://127.0.0.1:3000')
}

// 导出
exports.startServer = startServer;

重构上面的路由代码:

  • 将路由、处理函数和主程序分离,单独存放
  • 分工明确,各司其职,方便管理
//server.js
var http = require('http')
var url = require('url')   //url库
var querystring = require('querystring')

function startServer(route, handle) {
    var onRequest = function (req, res) {
        console.log('request received ' + req.url)
        var pathname = url.parse(req.url,true).pathname

        var data = ""
        req.on("error", function (err) {
            console.error(err)
        }).on("data", function (chunk) {
            data += chunk
        }).on("end", function () {
            if (req.mothod === "POST") {
                if (data.length > 1e6) {
                    req.connection.destroy() // 如果数据很大,就断开
                }
                route(handle, pathname, res, querystring.parse(data))
            } else {
                var params = url.parse(req.url, true).query
                route(handle, pathname, res, params)
            }
        })
        // 或者
        // var data = []
        // data.push(chunk)
        // data = Buffer.concat(data).toString()

    }
    var server = http.createServer(onRequest)
    server.listen(3000)
    console.log('server started on http://127.0.0.1:3000')
}

module.exports.startServer = startServer
//router.js
fs = require('fs')

function route(handle, pathname, res, params) {
    console.log('Routing a request for ' + pathname)
    if (typeof handle[pathname] === 'function') {
        handle[pathname](res, params)
    } else {
        console.log('No handle for ' + pathname)
        res.writeHead(200, { 'Content-Type': 'text/html' })
        fs.createReadStream(__dirname + '/404.html', 'utf8').pipe(res)
    }
}

module.exports.route = route
//handler.js
var fs = require('fs')

function home(res) {
    console.log('home')
    res.writeHead(200, { 'Content-Type': 'text/html' })
    fs.createReadStream(__dirname + '/index.html', 'utf8').pipe(res)
}

function review(res) {
    console.log('review')
    res.writeHead(200, { 'Content-Type': 'text/html' })
    fs.createReadStream(__dirname + '/review.html', 'utf8').pipe(res)
}

function api_records(res, params) {
    console.log('api_records')
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify(params))
}

module.exports = {
    home: home,
    review: review,
    api_records: api_records
}
//app.js
var server = require('./server')
var router = require('./router')
var handler = require('./handler')

var handle = {}
// key是路径,值是处理函数
handle['/'] = handler.home
handle['/home'] = handler.home
handle['/review'] = handler.review
handle['/api/v1/records'] = handler.api_records

server.startServer(router.route, handle)

15、web服务器使用get或post请求发送数据

有两种方式:通过地址栏和表单

地址栏是用get方法,表单是post方法。因为地址栏的数据是暴露出去的,所以通常用于查询数据,而通过表单传递数据一般用于提交一些信息。

querystring - 查询字符串

  • var querystring = require('querystring')
  • querystring.parse(data) 把一个 URL 查询字符串 str 解析成一个键值对的集合
// 接收请求数据,然后处理,查看request 类型
var data = ""
req.on("error", function (err) {
    console.error(err)
}).on("data", function (chunk) {
    data += chunk
}).on("end", function () {
    if (req.mothod === "POST") {
        if (data.length > 1e6) {
            req.connection.destroy() // 如果数据很大,就断开
        }
        route(handle, pathname, res, querystring.parse(data))
    } else {
        var params = url.parse(req.url, true).query
        route(handle, pathname, res, params)
    }
})
// 或者
// var data = []
// data.push(chunk)
// data = Buffer.concat(data).toString()

16、包管理器 npm

# Or alias it in .bashrc or .zshrc
echo '\n#alias for npm\nalias npm="npm --registry=https://registry.npm.taobao.org \
  --cache=$HOME/.npm/.cache/npm \
  --disturl=https://npm.taobao.org/dist \
  --userconfig=$HOME/.npmrc"' >> ~/.zshrc && source ~/.zshrc
  • yarn 也是包管理器,更快下载速度

17、package.json 文件

  • 记录项目中使用的包名,发布时不用包内容了,只要名称就行
  • npm init 提问式初始化项目信息,生成package.json文件,-y 全部默认
  • npm install --save xxx安装的同时,将信息写入package.json
  • npm install --save-dev xxx安装的同时,将信息写入package.json中的dev开发依赖
  • npm view moduleNames 查看node模块的package.json文件夹
  • npm run start 启动包,执行 package.json scripts 中的 start 命令,还有 stop restart test
  • npm install 安装 package.json 中记录的包

18、nodemon监控文件并重启服务

  • nodemon 用来监视应用中的任何文件更改并自动重启服务
  • 非常适合用在开发环境中,方便啊,不用手动操作了
  • 全局安装 npm install -g nodemon
  • 本地安装 npm install --save-dev nodemon
  • 启动应用 nodemon [your node app]
  • 获取修改 package.json 中的启动脚本,添加nodemon app.js, 用 npm start 直接启动,方便

相关文章

  • nodejs安装

    Node.js安装 目录 Node.js简单介绍 windows安装Node.js Linux安装Node.js ...

  • node.js基础

    什么是node.js Node.js特点 node.js优点和缺点

  • Nodejs.2

    参考内容:Node.js EventEmitter 四、Node.js EventEmitter Node.js所...

  • nodejs第一步

    Node.js 是什么?Node.js与JavaScript的区别是什么? Node.js的优点?Node.js的...

  • node 学习笔记.md

    Node.js第一天 1. 初识Node.js 1.1 Node.js是什么 Node.js® is a Java...

  • Node.js学习

    主线:Node.js是什么 --> Node.js的组成 --> Node.js的特点 --> Helloworl...

  • 使用AngularJS搭建前台框架

    Node.js部署: 下载安装包:从Node.js官网下载Node.js安装包。 安装Node.js:打开node...

  • Node.js模块

    Node.js 模块和 Node.js 包介绍。 一、Node.js模块 每一个Node.js都是一个Node.j...

  • 小鹅通视频下载mac 小鹅通课程下载教程

    前两天,Node.js官方发布了Node.js 15的正式版本,Node.js 15 将替代 Node.js 14...

  • node学习笔记

    node.js 介绍 node.js初识 node.js 平台是基于 Chrome V8 JavaScript 引...

网友评论

      本文标题:Node.js

      本文链接:https://www.haomeiwen.com/subject/hubbhctx.html