nodejs入门(一)

文章目录

NodeJs介绍安装开发工具配置

Nodejs介绍

Node.js是一个Javascript运行环境(runtime)。它让JavaScript可以开发后端程序,它几乎能实现其他后端语言能实现的所有功能。

Nodejs是基于Google V8引擎,V8引擎是 Google 发布的一款开源的JavaScript引擎,原来主要用于Chrome浏览器的JS解释部分,但是Ryan Dahl这哥们,鬼才般的,把这个V8引擎搬到了服务器上,用于做服务器的软件

Nodejs官网:https://nodejs.org/en/
Npm包管理:https://www.npmjs.com/

为什么要学Nodejs

Nodejs用户量大:我们无法统计Nodejs软件的下载量,但是我们可以通过Nodejs框架Express的下载量来分析出Nodejs的用户量非常惊人。Nodejs在2017年的时候用户量已经过千万。经过了3年的发展,Nodejs目前的用户量可想而知

!(https://img-blog.csdnimg.cn/20200824163646406.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3plbmdyYW9saQ==,size_16,color_FFFFFF,t_70#pic_center)

Nodejs最擅长高并发:Nodejs最擅长的就是处理高并发,在Java、PHP或者.net等服务器端语言中,会为每一个客户端连接创建一个新的线程。而每个线程需要耗费大约2MB内存。也就是说,理论上,一个8GB内存的服务器可以同时连接的最大用户数为4000个左右。要让Web应用程序支持更多的用户,就需要增加服务器的数量,而Web应用程序的硬件成本当然就上升了。Node.js不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,通过非阻塞I/O、事件驱动机制,让Node.js程序宏观上也是并行的。使用Node.js,一个8GB内存的服务器,可以同时处理超过4万用户的连接

Nodejs简单:NodeJs语法完全是js语法,只要你懂JS基础就可以学会Nodejs后端开发。使得Nodejs具有开发周期短、开发成本低、学习成本低等优势

Nodejs可实现的功能多:Nodejs 不仅可以像其他后端语言一样写动态网站、写接口,还可以应用在云计算平台、游戏开发、区块链开发、即时通讯、跨平台App开发、桌面应用开发(electron)、云直播、物联网领域等

NodeJs环境搭建

官网:https://nodejs.org/en/

下载地址:https://nodejs.org/en/download/

下载稳定版本、双击下一步下一步安装。

安装完成重新打开CMD,输入node -v查看当前版本

在windows还可以使用nvm来安装node,参考:

开发工具配置

vscode,新建一个app.js,内容如下

console.log("hello js");

在终端上执行node app.js可以看到输出如下

Node.js HTTP模块、URL模块 supervisor工具

Node.js 创建第一个应用

如果我们使用PHP来编写后端的代码时,需要Apache 或者 Nginx 的HTTP 服务器,来处理客户端的请求相应。不过对 Node.js 来说,概念完全不一样了。使用 Node.js 时,我们不仅仅在实现一个应用,同时还实现了整个 HTTP 服务器

引入http模块

// 表示引入http模块
var http = require('http');

创建服务器

新建app.js,如果在vscode中安装了Node Snippets,则只需要输入node-ht就会有提示

完整的代码如下

// 表示引入http模块
var http = require('http');
// 创建一个服务器,回调函数表示接收到请求之后做的事情
http.createServer(function (request, response) {
  // req参数表示请求,res表示响应
  response.writeHead(200, {'Content-Type': 'text/plain'});
  response.end('Hello World'); // End 方法使 Web 服务器停止处理脚本并返回当前结果
}).listen(8081);

console.log('Server running at http://127.0.0.1:8081/');

自己手动写一个

const http = require('http');
http.createServer(function(req, res){ // req:获取客户端传过来的信息,res:给浏览器响应信息
    console.log(req.url);
    res.writeHead(200, {"Content-Type": "text/html, charset='utf-8'"});
    res.write('this is nodejs');
    res.end(); // 结束响应

}).listen(8081);

console.log('Server running at http://127.0.0.1:8081/');

运行程序

安装完成重新打开CMD,或者在vscode的终端中运行

node app1.js

浏览器访问链接

如果想要输出对应的http头(vscode中可以用快捷键生成h5代码),则使用如下内容

res.write('你好 nodejs');
res.write("<head><meta charset='UTF-8'></head>");

你会发现,我们本地写一个js,打死都不能直接拖入浏览器运行,但是有了node,我们任何一个js文件,都可以通过node来运行。也就是说,node就是一个js的执行环境

HTTP模块、URL模块

HTTP模块的使用

上面其实就是http模块的使用了

URL模块的使用

url模块在cmd下即可演示,在cmd中输入node,然后依次敲入如下命令即可看到效果

url.parse("http://www.baidu.com?a=xxx")
url.parse("http://www.baidu.com?a=xxx", true) // 转换成了对象

输出如下

假如需要在程序中拿到上面的参数,那么代码如下,在vscode中执行

u = require('url');

var api = "http://www.baidu.com?name=zhangsan&age=37";
var getValue = u.parse(api, true).query;
console.log(getValue); // [Object: null prototype] { name: 'zhangsan', age: '37' }
// 获取姓名和age
console.log(`姓名:${getValue.name}--年龄:${getValue.age}`); // 输出性能:zhangsan--年龄:37

修改之前的http服务器,让其能够获取url中的参数

http = require('http');
url = require('url');
http.createServer(function(req, res){ // req:获取客户端传过来的信息,res:给浏览器响应信息
    res.writeHead(200, {"Content-Type": "text/html, charset='utf-8'"});
    res.write('你好 nodejs');
    res.write("<head><meta charset='UTF-8'></head>");
    console.log(req.url); // 获取浏览器访问的地址
    if("/favicon.ico" != req.url)
    {
        var userInfo = url.parse(req.url, true).query;
        console.log(`姓名:${userInfo.name}--年龄:${userInfo.age}`); // 输出性能:zhangsan--年龄:37
    }
    res.end(); // 结束响应
}).listen(8081);

console.log('Server running at http://127.0.0.1:8081/');

浏览器中访问url:http://127.0.0.1:8081/?name=zhangsan&age=37,可以看到输出内容如下

Server running at http://127.0.0.1:8081/
/name=zhangsan&age=37
姓名:undefined--年龄:undefined
/favicon.ico
/?name=zhangsan&age=37
姓名:zhangsan--年龄:37
/favicon.ico

Nodejs自启动工具supervisor

supervisor会不停的watch你应用下面的所有文件,发现有文件被修改,就重新载入程序文件这样就实现了部署,修改了程序文件后马上就能看到变更后的结果。再也不用担心我的重启nodejs了

简单来说就是,避免每次修改后都ctrl+c结束,在重新运行

首先安装supervisor

npm install -g supervisor

使用supervisor代替node命令启动应用

用supervisor.cmd .\app1.js启动js

PS C:\Users\zeng\Desktop\nodejs\nodedemo02> supervisor.cmd .\app1.js

Running node-supervisor with
  program '.\app1.js'
  --watch '.'
  --extensions 'node,js'
  --exec 'node'

Starting child process with 'node .\app1.js'
Watching directory 'C:\Users\zeng\Desktop\nodejs\nodedemo02' for changes.
Press rs for restarting the process.
Server running at http://127.0.0.1:8081/

随便修改js文件,立马生效不需要重启程序

CommonJs 和 Nodejs 模块、自定义模块

什么是CommonJs

JavaScript是一个强大面向对象语言,它有很多快速高效的解释器。然而, JavaScript标准定义的API是为了构建基于浏览器的应用程序。并没有制定一个用于更广泛的应用程序的标准库。CommonJS规范的提出,主要是为了弥补当前JavaScript没有标准库的缺陷。它的终极目标就是:提供一个类似Python,Ruby和Java语言的标准库,而不只是让JavaScript停留在小脚本程序的阶段。用CommonJS API编写出的应用,不仅可以利用JavaScript开发客户端应用,而且还可以编写以下应用

  • 服务器端JavaScript应用程序。(nodejs)
  • 命令行工具。
  • 桌面图形界面应用程序。

CommonJS就是模块化的标准,nodejs就是CommonJS(模块化)的实现

Nodejs中的模块化

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

在Node中,模块分为两类

一类是Node提供的模块,称为核心模块;另一类是用户编写的模块,称为文件模块。

  • 核心模块部分在Node源代码的编译过程中,编译进了二进制执行文件。在Node进程启动时,部分核心模块就被直接加载进内存中,所以这部分核心模块引入时,文件定位和编译执行这两个步骤可以省略掉,并且在路径分析中优先判断,所以它的加载速度是最快的。如:HTTP模块 、URL模块、Fs模块都是nodejs内置的核心模块,可以直接引入使用。
  • 文件模块则是在运行时动态加载,需要完整的路径分析、文件定位、编译执行过程、速度相比核心模块稍微慢一些,但是用的非常多。这些模块需要我们自己定义。接下来我们看一下nodejs中的自定义模块。

CommonJS(Nodejs)中自定义模块的规定

我们可以把公共的功能抽离成为一个单独的 js 文件作为一个模块,默认情况下面这个模块里面的方法或者属性,外面是没法访问的。如果要让外部可以访问模块里面的方法或者属性,就必须在模块里面通过exports 或者module.exports暴露属性或者方法

在需要使用这些模块的文件中,通过require的方式引入这个模块。这个时候就可以使用模块里面暴露的属性和方法

对一个普通函数最修改

一个普通的js函数,help.js,其内容如下

function formatApi(api){
    return "https://www.baidu.com/"+api;
}

http = require('http');
http.createServer(function(req, res){ // req:获取客户端传过来的信息,res:给浏览器响应信息
    res.writeHead(200, {"Content-Type": "text/html, charset='utf-8'"});
    res.write('你好 nodejs <br>');
    res.write("<head><meta charset='UTF-8'></head>");
    res.write(formatApi("api/list"));
    res.end(); // 结束响应
}).listen(8081);

console.log('Server running at http://127.0.0.1:8081/');

新建另外一个文件main.js,引入并调用这个formatApi函数,此时应该修改help.js


function formatApi(api){
    return "https://www.baidu.com/"+api;
}

exports.formatApi=formatApi; // 导出函数,让其他js能访问

main.js内容如下

http = require('http');
helps = require('./helps.js');

http.createServer(function(req, res){ // req:获取客户端传过来的信息,res:给浏览器响应信息
    res.writeHead(200, {"Content-Type": "text/html, charset='utf-8'"});
    res.write('你好 nodejs <br>');
    res.write("<head><meta charset='UTF-8'></head>");
    res.write(helps.formatApi("api/list2"));
    res.end(); // 结束响应
}).listen(8081);

console.log('Server running at http://127.0.0.1:8081/');

定义使用模块

使用第二种方式暴露方法,如果你把所有东西都包装在了tools变量中,那么建议采用module.exports的方式暴露,如果方法是独立的,则一个个使用exports进行暴露

// 定义一个tools.js的模块
//模块定义
var tools = {
  sayHello: function() {
    return 'hello NodeJS';
  },
  add: function(x, y) {
    return x + y;
  }
};
// 模块接口的暴露
// module.exports = tools;
exports.sayHello = tools.sayHello;
exports.add = tools.add;

在main2.js中使用该模块

http = require('http');
helps = require('./tools.js'); // 省略掉后缀.js也是可以的

http.createServer(function(req, res){ // req:获取客户端传过来的信息,res:给浏览器响应信息
    res.writeHead(200, {"Content-Type": "text/html, charset='utf-8'"});
    res.write('你好 nodejs <br>');
    res.write("<head><meta charset='UTF-8'></head>");
    res.write(helps.sayHello());
    res.end(); // 结束响应
}).listen(8081);

console.log('Server running at http://127.0.0.1:8081/');

引入文件不一样的玩法,node_modules文件夹与index.js

在项目中新建一个node_modules文件夹,把上面的helps.js放到中间,修改文件名为index.js,此时项目的文件夹是这样的

在main3.js中使用该模块(这样就和引入系统模块一致了)

http = require('http');
// 完整路径引入
// helps = require('./node_modules/axios/index');
// 省略默认的node_modules
// helps = require('axios/index');
// 省略默认的index名
helps = require('axios');
console.log(helps.formatApi("api/list"));

npm init 生成package.json

如果按照上面来说,如果只写调用的文件夹,默认自动查找index.js,但使用package则可以进行更改

新建一个db文件夹,将上面的index.js拷过去,重命名为db.js,此时项目的文件夹是这样的:

cmd中进入db文件夹执行如下操作

npm init --yes

可以看到生成了package.json,里面指定main即为db.js,在main4.js中使用该模块,现在已经正常输出了:

helps = require('db');
console.log(helps.formatApi("api/list"));

Nodejs中的包、npm 、第三方模块、 package.json以及cnpm

包与NPM

Nodejs中除了它自己提供的核心模块外,我们可以自定义模块,也可以使用第三方的模块。Nodejs中第三方模块由包组成,可以通过包来对一组具有相互依赖关系的模块进行统一管理

完全符合CommonJs规范的包目录一般包含如下这些文件

  • package.json :包描述文件
  • bin :用于存放可执行二进制文件的目录
  • lib :用于存放JavaScript代码的目录
  • doc :用于存放文档的目录

在NodeJs中通过NPM命令来下载第三方的模块(包)

NPM介绍

npm是世界上最大的开放源代码的生态系统。我们可以通过npm下载各种各样的包,这些源代码(包)我们可以在https://www.npmjs.com找到。

npm是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种:

  • 允许用户从NPM服务器下载别人编写的第三方包到本地使用。(silly-datetime)
  • 允许用户从NPM服务器下载并安装别人编写的命令行程序(工具)到本地使用。(supervisor)
  • 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。

NPM命令详解

npm -v查看npm版本

使用npm命令安装模块

npm install  Module Name
// 如安装jq模块:
npm install jquery

npm uninstall moudleName 卸载模块

npm uninstall  ModuleName

npm list 查看当前目录下已安装的node包

npm list

npm info jquery 查看jquery的版本

npm info 模块 //查看模块的版本

指定版本安装 npm install jquery@1.8.0

尝试安装一个md5模块

下面是尝试安装一个md5模块的流程,首先去https://www.npmjs.com找md5对应的模块

这是他自带的说明:https://www.npmjs.com/package/md5

首先进入到nodedemo5中,用命令安装md5模块

npm install md5

安装完成后的文件夹如下,有他的模块以及他使用的模块

新建一个main.js去使用这模块

var md5 = require('md5');
console.log(md5('message'));

如果你的main.js是在安装模块之前init的,那么建议加上save,这样就能添加到package.json的dependencies中,如果在之后,init,会自己识别

npm install md5 --save

package.json

package.json定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)

创建package.json

npm init 或者 npm init –yes

package.json文件

假设当前没有node_modules文件夹,只有一个.json

{
  "name": "test",
  "version": "1.0.0",
  "description": "test",
  "main": "main.js",
  "keywords": [
    "test"
  ],
  "author": "wade",
  "license": "MIT",
  "dependencies": {
    "express": "^4.10.1"
  },
  "devDependencies": {
    "jslint": "^0.6.5"
  }
}

此时执行npm -i,会自动拉取dependencies中的相关模块到node_modules文件夹中

安装模块并把模块写入package.json(依赖)

npm install  babel-cli  --save-dev
npm install 模块 --save
npm install 模块 --save-dev // 写入到devDependencies中

dependencies与devDependencies之间的区别?

使用npm install node_module –save自动更新dependencies字段值;
使用npm install node_module –save-dev自动更新devDependencies字段值;

dependencie 配置当前程序所依赖的其他包
devDependencie 配置当前程序所依赖的其他包,比如一些工具之类的配置在这里

"dependencies": {
 "ejs": "^2.3.4",
 "express": "^4.13.3",
 "formidable": "^1.0.17"
}

相关说明如下

  • ^表示第一位版本号不变,后面两位取最新的
  • ~表示前两位不变,最后一个取最新
  • *表示全部取最新

安装淘宝镜像

http://www.npmjs.org npm包官网

https://npm.taobao.org/ 淘宝npm镜像官网

淘宝NPM镜像是一个完整npmjs.org镜像,你可以用此代替官方版本(只读),同步频率目前为10分钟一次以保证尽量与官方服务同步

我们可以使用我们定制的 cnpm (gzip 压缩支持) 命令行工具代替默认的npm:

npm install -g cnpm --registry=https://registry.npm.taobao.org

NodeJs FS模块

fs.stat 检测是文件还是目录

新建一个01.js,内容如下

/*jshint esversion: 6 */
var fs = require('fs');
fs.stat('01.js', (error, stats) =>{
     if(error){
        console.log(error);
    } 
    else { 
        console.log(stats);
        console.log(`文件:${stats.isFile()}`);
        console.log(`目录:${stats.isDirectory()}`);
    } 
});

fs.mkdir 创建目录

/*jshint esversion: 6 */
var fs = require('fs');
fs.mkdir('logs', (error) =>{
    if (error) {
        console.log(error);
    } else {
        console.log('成功创建目录:logs');
    }
});

fs.writeFile 创建写入文件

/*jshint esversion: 6 */
var fs = require('fs');
fs.writeFile('logs/hello.log', '您好 ~ \n', (error) =>{
    if (error) {
        console.log(error);
    } else {
        console.log('成功写入文件');
    }
});

fs.appendFile 追加文件

/*jshint esversion: 6 */
var fs = require('fs');
fs.appendFile('logs/hello.log', 'hello ~ \n', (error) =>{
    if (error) {
        console.log(error);
    } else {
        console.log('成功写入文件');
    }
});

fs.readFile 读取文件

/*jshint esversion: 6 */
var fs = require('fs');
fs.readFile('logs/hello.log', 'utf8', (error, data) =>{
    if (error) {
        console.log(error);
    } else {
        console.log(data);
    }
});

fs.readdir读取目录

/*jshint esversion: 6 */
var fs = require('fs');
fs.readdir('logs', (error, files) =>{
    if (error) {
        console.log(error);
    } else {
        console.log(files);
    }
});

fs.rename 重命名

/*jshint esversion: 6 */
var fs = require('fs');
fs.rename('logs/hello.log', 'logs/greeting.log', (error) =>{
    if (error) {
        console.log(error);
    } else {
        console.log('重命名成功');
    }
});

fs.rmdir 删除目录,也只能删除目录

/*jshint esversion: 6 */
var fs = require('fs');
fs.rmdir('log', (error) =>{ // log为一个空目录
    if (error) {
        console.log(error);
    } else {
        console.log('成功的删除了目录:log');
    }
});

fs.unlink删除文件

/*jshint esversion: 6 */
var fs = require('fs');
var file = "greeting.log";
fs.unlink(`logs/${file}`, (error) =>{
    if (error) {
        console.log(error);
    } else {
        console.log(`成功的删除了文件: ${file}`);
    }
});

fs.createReadStream 从文件流中读取数据

新建一个测试json文件:

{
    "seller": {
      "name": "粥品香坊(回龙观)",
      "description": "蜂鸟专送",
      "deliveryTime": 38,
      "score": 4.2,
      "serviceScore": 4.1,
      "foodScore": 4.3,
      "rankRate": 69.2,
      "minPrice": 20,
      "deliveryPrice": 4,
      "ratingCount": 24,
      "sellCount": 90
    }
}

一个读取的js文件:

/*jshint esversion: 6 */
const fs = require ('fs');

var fileReadStream = fs .createReadStream('data.json');
let count = 0; // 当文件越大,读取的次数越多
var str = ''; // 保存所有数据

// 每一次读取都会触发data事件
fileReadStream.on('data', (chunk) => { // on表示接收这个广播
   console.log(`${ ++ count } 接收到:${chunk.length}`); 
   str += chunk;
});

fileReadStream.on('end', () => {
   console.log('--- 结束 ---'); 
   console.log( count ); 
   console.log( str );
});

fileReadStream.on('error', (error) => {
   console.log(error); 
});

fs.createWriteStream 写入文件

/*jshint esversion: 6 */
var fs = require("fs");
var data = '我是从数据库获取的数据,我要保存起来';
// 创建一个可以写入的流,写入到文件 output.txt 中 
var writerStream = fs.createWriteStream('output.txt');
// 使用 utf8 编码写入数据 
writerStream.write(data,'UTF8');
// 标记文件末尾 
writerStream.end();
// 处理流事件 -- > finish 事件 
writerStream.on('finish', function() {
   /*finish - 所有数据已被写入到底层系统时触发。 */ 
 console.log("写入完成。");
});
writerStream.on('error', function(err){
 console.log(err.stack);
});
console.log("程序执行完毕");

管道流

管道提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中

如上面的图片所示,我们把文件比作装水的桶,而水就是文件里的内容,我们用一根管子(pipe)连接两个桶使得水从一个桶流入另一个桶,这样就慢慢的实现了大文件的复制过程。 以下实例我们通过读取一个文件内容并将内容写入到另外一个文件中。

/*jshint esversion: 6 */
var fs = require("fs");
// 创建一个可读流 
var readerStream = fs.createReadStream('data.json');
// 创建一个可写流 
var writerStream = fs.createWriteStream('output.txt');
// 管道读写操作 
// 读取 input.txt 文件内容,并将内容写入到output.txt文件中 
readerStream.pipe(writerStream );
console.log("程序执行完毕");

两个常用的例子和在循环中调用异步函数的错误

/*jshint esversion: 6 */
var fs = require('fs');

// //1.判断服务器上面有没有upload目录。没有创建这个目录。 (图片上传)
// fs.stat('upload', function(err,stats){
//        if(err){  /*没有这个目录*/
//            fs.mkdir('upload',function(error){
//                if(error){
//                    console.log(error);
//                    return false;
//                }
//                console.log('创建成功');
//            });
//        }else{
//            console.log('目录已经存在');
//            console.log(stats.isDirectory());
//        }
// });


// // 2. 找出html目录下面的所有的目录,然后打印出来
// fs.readdir('html',function(err,files) {
//         if(err){
//             console.log(error);
//         }else{  /*判断是目录还是文件夹*/
//             console.log(files);  /*数组*/
//             for(var i=0;i<files.length;i++){ // 异步的for循环非常快
//                 console.log(files[i]);
//                 fs.stat(files[i], function(error, stats){  /*循环判断是目录还是文件  ---fs.stat是一个异步函数 错误写法*/
//                     console.log(i, files[i]);
//                 });
//             }
//         }
// });


// for(var i=0; i<3;i++) {
//    setTimeout(function(){ // setTimeout是一个异步
//        console.log(i);
//    },100);
// }


// 正确的写法
var filesArr=[];
fs.readdir('html',function(err, files) {
    if(err) {
        console.log(error);
    } else {  /*判断是目录还是文件夹*/
        // console.log(files);  /*数组*/
        (function getFile(i){
            if(i==files.length){  /*循环结束*/
                console.log('目录:');
                console.log(filesArr);  /*打印出所有的目录*/
                return false;
            }
            // files[i] = css js news.html
            // 注意:目录
            fs.stat('html/'+files[i],function(error,stats) {  /*循环判断是目录还是文件  ---异步 错误写法*/
                if(stats.isDirectory()){ /*目录*/
                    filesArr.push (files[i]);  /*保存数据*/
                }
                // 递归掉用
                getFile(i+1);
            });
        })(0); // 传入getFile从0开始
    }
});

Nodejs新特性 async await 的使用以及使用 async await 处理异步

Es6 常见语法的使用

    1. let const
    1. 箭头函数
    1. 对象、属性的简写
    1. 模板字符串
    1. Promise

相关的例子如下

/*jshint esversion: 6 */

// 1、let const的使用 let和var是一样的用来定义变量
// let是一个块作用域
if(true) {
    let a = 123;
    var b = 456; // 如果是var是可以的
}
// console.log(a); // ReferenceError: a is not defined
console.log(b);

// 2、模板字符串
// 一般打印一个字符串如下
var name = "张三";
var age = 51;
console.log(name + '的年龄是' + age);
// 使用模板字符串的形式
console.log(`${name}的年龄是${age}`);
// 一个比较使用的例子
var name2 = "zhangsan";
var app = {
    "name": name2
};
var app2 = {
    name2 // 如果属性名称和变量同一个名,那么可以省略
};
console.log(app.name, app2.name2);

// 3、方法的简写
var name3 = 'zhangsan';
var app = {
    name,
    // 未简写前的run方法
    // run:function() {
    //     console.log(`${this.name}在跑步1`);
    // }
    // 简写后的run方法
    run() {
        console.log(`${this.name}在跑步`);
    }
};
app.run();

// // 4、箭头函数 this指向上下文
// setTimeout(function(){
//     console.log('执行');
// }, 1000);

// setTimeout(()=>{
//     console.log('执行');
// }, 2000);

// 4、获取异步方法的数据
// 常规方法使用callback
function getData(callback) {
    // ajax
    setTimeout(()=>{
        console.log('执行');
        callback('zengraoli');
    }, 1000);
}
getData(function(aaa){
    console.log(aaa);
});

// 使用Promise,es6以后出来的Promise
var p = new Promise(function(resolve, rejects){
    setTimeout(()=>{
        console.log('执行');
        resolve('zengraoli');
    }, 1000);
});

p.then(function(data){
    console.log(data);
});

// 稍微封装一下
function getData2(resolve, rejects) {
    // ajax
    setTimeout(()=>{
        console.log('执行22');
        resolve('zengraoli2');
    }, 1000);
}

var p2 = new Promise(getData2);
p2.then(function(data){
    console.log(data);
});

Async、Await 和Promise 的使用

async 是“异步”的简写,而await 可以认为是async wait 的简写。所以应该很好理解async用于申明一个异步的function ,而await 用于等待一个异步方法执行完成。

简单理解:

  • async 是让方法变成异步。
  • await 是等待异步方法执行完成。

详细说明:
async 是让方法变成异步,在终端里用node执行这段代码,你会发现输出了Promise {‘Hello async’ },这时候会发现它返回的是Promise

/*jshint esversion: 8 */
// 普通方法
function test() {
    return '您好nodejs';
}
console.log(test());

// 改成异步方法
async function test2(){   
    return '您好nodejs';
}
console.log(test2());  //  Promise { '您好nodejs' }

await 在等待async方法执行完毕,其实await等待的只是一个表达式,这个表达式在官方文档里说的是Promise 对象,但是它也可以接受普通值。注意:await 必须在async方法中才可以使用因为await访问本身就会造成程序停止堵塞,所以必须在异步方法中才可以使用

/*jshint esversion: 8 */
// await只能用在异步方法中
// 一个错误的例子
async function test3(){   //  Promise { '您好nodejs' }
    return '您好nodejs2';
}
// console.log(await test());  //错误:await必须得用在async的方法里面

async function main(){
    var data = await test3();  //获取异步方法里面的数据
    console.log(data);
}
main();

async/await 同时使用
async 会将其后的函数(函数表达式或Lambda)的返回值封装成一个Promise 对象,而 await 会等待这个Promise 完成,并将其resolve 的结果返回出来

/*jshint esversion: 8 */
// 如果仅仅是返回字符串,则根本没必要使用async,下面是正规使用场景
async function test4() {   //  Promise { '您好nodejs' }
    return new Promise((resolve, rejects)=> {
        setTimeout(function(){
            var name = "zengraoli";
            resolve(name);
        }, 1000);
    });
}

async function main2(){
    var data = await test4();  //获取异步方法里面的数据
    console.log(data);
}
main2();

一个用异步来获取文件夹下所有子文件夹名的例子

/*jshint esversion: 8 */
// 练习:wwwroot文件夹下面有images css js 以及index.html , 找出 wwwroot目录下面的所有的目录,然后放在一个数组中
var fs = require('fs');
// 这是之前使用递归获取文件夹下所有的目录名
var path='./wwwroot';
var dirArr=[];
fs.readdir(path,(err,data)=>{
    if(err){
        console.log(err);
        return;
    }
    (function getDir(i){
        if(i==data.length){ //执行完成
            console.log(dirArr);
            return;
        }
        fs.stat(path+'/'+data[i],(error,stats)=>{
            if(stats.isDirectory()){
                dirArr.push(data[i]);
            }
            getDir(i+1);
        });
    })(0);
});

// 1、定义一个isDir的方法判断一个资源到底是目录还是文件
async function isDir(path) {
    return new Promise((resolve,reject) => {
        fs.stat(path, (error, stats) => {
            if (error) {
                console.log(error);
                reject(error);
                return;
            }
            if (stats.isDirectory()) {
                resolve(true);
            } else {
                resolve(false);
            }
        });
    });
}
// 2、获取wwwroot里面的所有资源  循环遍历 
function main(){
    var path='./wwwroot';
    var dirArr=[];
    fs.readdir(path, async (err,data)=>{  //注意,用到await的最靠近的方法修改成async
        if(err){
            console.log(err);
            return;
        }    
        for(var i=0;i<data.length;i++){
            if(await isDir(path+'/'+data[i])){
                dirArr.push(data[i]);
            }
        }
        console.log(dirArr);
    });
}
main();

全文所涉及的代码下载地址

参考链接

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值