Node — 第四天(Promise与路由)

Promise - ES6新对象

Promise能够处理异步程序。

回调地狱

在这里插入图片描述

JS中或node中,都大量的使用了回调函数进行异步操作,而异步操作什么时候返回结果是不可控的,如果我们希望几个异步请求按照顺序来执行,那么就需要将这些异步操作嵌套起来,嵌套的层数特别多,就叫做回调地狱。

下面的案例就有回调地狱的意思:

案例:有 a.txt、b.txt、c.txt三个文件,使用fs模板按照顺序来读取里面的内容,代码:

// 将读取的a、b、c里面的内容,按照顺序输出
const fs = require('fs');// 读取a文件
fs.readFile('./a.txt', 'utf-8', (err, data) => {if (err) throw err;console.log(data.length);// 读取b文件fs.readFile('./b.txt', 'utf-8', (err, data) => {if (err) throw err;console.log(data);// 读取c文件fs.readFile('./c.txt', 'utf-8', (err, data) => {if (err) throw err;console.log(data);});});
});

案例中,只有三个文件,试想如果需要按照顺序读取的文件非常多,那么嵌套的代码将会多的可怕,这就是回调地狱的意思。

Promise简介

  • Promise对象可以解决回调地狱的问题
  • Promise 是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理和更强大
  • Promise可以理解为一个容器,里面可以编写异步程序的代码
  • 从语法上说,Promise 是一个对象,使用的使用需要 new

Promise简单使用

Promise是“承诺”的意思,实例中,它里面的异步操作就相当于一个承诺,而承诺就会有两种结果,要么完成了承诺的内容,要么失败。

所以,使用Promise,分为两大部分,首先是有一个承诺(异步操作),然后再兑现结果。

第一部分:定义“承诺”

// 实例化一个Promise,表示定义一个容器,需要给它传递一个函数作为参数,而该函数又有两个形参,通常用resolve和reject来表示。该函数里面可以写异步请求的代码
// 换个角度,也可以理解为定下了一个承诺
let p = new Promise((resolve, reject) => {// 形参resolve,单词意思是 完成// 形参reject ,单词意思是 失败fs.readFile('./a.txt', 'utf-8', (err, data) => {if (err) {// 失败,就告诉别人,承诺失败了reject(err);} else {// 成功,就告诉别人,承诺实现了resolve(data.length);}  });
});

第二部分:获取“承诺”的结果

// 通过调用 p 的then方法,可以获取到上述 “承诺” 的结果
// then方法有两个函数类型的参数,参数1表示承诺成功时调用的函数,参数2可选,表示承诺失败时执行的函数
p.then((data) => {},(err) => {}
);

完整的代码:

const fs = require('fs');
// promise 承诺// 使用Promise分为两大部分// 1. 定义一个承诺
let p = new Promise((resolve, reject) => {// resolve -- 解决,完成了; 是一个函数// reject  -- 拒绝,失败了; 是一个函数// 异步操作的代码,它就是一个承诺fs.readFile('./a.txt', 'utf-8', (err, data) => {if (err) {reject(err);} else {resolve(data.length);}});
});// 2. 兑现承诺
// p.then(
//     (data) => {}, // 函数类似的参数,用于获取承诺成功后的数据
//     (err) => {} // 函数类型的参数,用于或承诺失败后的错误信息
// );
p.then((data) => {console.log(data);},(err) => {console.log(err);}
);

then方法的链式调用

  • 前一个then里面返回的字符串,会被下一个then方法接收到。但是没有意义;

  • 前一个then里面返回的Promise对象,并且调用resolve的时候传递了数据,数据会被下一个then接收到

  • 前一个then里面如果没有调用resolve,则后续的then不会接收到任何值

    const fs = require('fs');
    // promise 承诺new Promise((resolve, reject) => {fs.readFile('./a.txt', 'utf-8', (err, data) => {err ? reject(err) : resolve(data.length);});
    })
    .then((a) => {console.log(a);return new Promise((resolve, reject) => {fs.readFile('./a.txt', 'utf-8', (err, data) => {err ? reject(err) : resolve(data.length);});});
    })
    .then((b) => {console.log(b);return new Promise((resolve, reject) => {fs.readFile('./a.txt', 'utf-8', (err, data) => {err ? reject(err) : resolve(data.length);});});
    })
    .then((c) => {console.log(c)
    })
    .catch((err) => {console.log(err);
    });
    

    catch 方法可以统一获取错误信息

封装按顺序异步读取文件的函数

function myReadFile(path) {return new Promise((resolve, reject) => {fs.readFile(path, 'utf-8', (err, data) => {err ? reject(err) : resolve(data.length);})});
}myReadFile('./a.txt')
.then((a) => {console.log(a);return myReadFile('./b.txt');
})
.then((b) => {console.log(b);return myReadFile('./c.txt');
})
.then((c) => {console.log(c)
})
.catch((err) => {console.log(err);
});

async 和 await 修饰符

ES6 — ES2015

async 和 await 是 ES2017 中提出来的。

异步操作是 JavaScript 编程的麻烦事,麻烦到一直有人提出各种各样的方案,试图解决这个问题。

从最早的回调函数,到 Promise 对象,再到 Generator 函数,每次都有所改进,但又让人觉得不彻底。它们都有额外的复杂性,都需要理解抽象的底层运行机制。

异步I/O不就是读取一个文件吗,干嘛要搞得这么复杂?异步编程的最高境界,就是根本不用关心它是不是异步。

async 函数就是隧道尽头的亮光,很多人认为它是异步操作的终极解决方案

ES2017提供了async和await关键字。await和async关键词能够将异步请求的结果以返回值的方式返回给我们。

  • async 用于修饰一个 function
  • async 修饰的函数,表示该函数里面有异步操作(Promise的调用)
  • await和async需要配合使用,没有async修饰的函数中使用await是没有意义的,会报错
  • await需要定义在async函数内部,await后面跟的一般都是一个函数(函数里面包含有Promise)的调用
  • await修饰的异步操作,可以使用返回值的方式去接收异步操作的结果
  • 如果有哪一个await操作出错了,会中断async函数的执行

总结来说:async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果

const fs = require('fs');
// 将异步读取文件的代码封装
function myReadFile (path) {return new Promise((resolve, reject) => {fs.readFile(path, 'utf-8', (err, data) => {err ? reject(err) : resolve(data.length);});})
}async function abc () {let a = await myReadFile('./a.txt');let b = await myReadFile('./b.txt');let c = await myReadFile('./c.txt');console.log(b);console.log(a);console.log(c);
}abc();

路由

什么是路由

广义上来讲,路由就是映射关系

在这里插入图片描述

程序中的路径也是映射关系:

Express 中的路由

在 Express 中,路由指的是客户端的请求与服务器处理函数之间的映射关系。
Express 中的路由分 3 部分组成,分别是请求的类型、请求的 URL 地址、处理函数,格式如下

// 路径 ,就是我们之前说的接口的处理程序
app.get('/api/getbooks', (req, res) => {});app.post('/api/addbook', (req, res) => {});

每当一个请求到达服务器之后,需要先经过路由的匹配,只有匹配成功之后,才会调用对应的处理函数。

在匹配时,会按照路由的顺序进行匹配,如果请求类型和请求的 URL 同时匹配成功,则 Express 会将这次请求,转 交给对应的 function 函数进行处理。

模块化路由

为了方便对路由进行模块化的管理,Express 不建议将路由直接挂载到 app 上,而是推荐将路由抽离为单独的模块。 将路由抽离为单独模块的步骤如下:

  1. 创建路由模块对应的 .js 文件

    1. 创建router/login.js 存放 登录、注册、验证码三个路由
    2. 创建router/heroes.js 存放 和英雄相关的所有路由
  2. 调用 express.Router() 函数创建路由对象

    const express = require('express');
    const router = express.Router();
    
  3. 向路由对象上挂载具体的路由

    // 把app换成router,比如
    router.get('/xxx/xxx', (req, res) => {});
    router.post('/xxx/xxx', (req, res) => {});
    
  4. 使用 module.exports 向外共享路由对象

    module.exports = router;
    
  5. 使用 app.use() 函数注册路由模块 – app.js

    // app.js 中,将路由导入,注册成中间件
    const login = require('./router/logon.js');
    app.use(login)// app.use(require('./router/heroes.js'));
    app.use( require(path.join(__dirname, 'router', 'heores.js')) );
    

为路由模块添加前缀

我们可以省略路由模块中的 /api 前缀,而是在注册中间件的时候,统一设置。

app.use('/api', router);

具体:

app.js中:

// 导入路由模块,并注册成中间件
app.use('/api',  require(path.join(__dirname, 'router', 'login.js'))  );
app.use('/my',  require(path.join(__dirname, 'router', 'heroes.js'))  );

路由文件中,把前缀 /api 和 /my 去掉

使用路由模块的好处

  • 分模块管理路径,提高了代码的可读性
  • 可维护性更强
  • 减少路由的匹配次数
  • 权限管理更方便
  • etc…

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247994.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

winform datagridview控件使用

最近做项目时&#xff0c;显示查询结果总需要绑定到datagridview控件上显示&#xff0c;总结了给datagridview绑定数据的方式&#xff0c;以及导出datagridview数据到excel表格&#xff0c;如有错误请多指教 1.直接绑定数据源&#xff0c;可以绑定的数据格式有List<T>,Da…

Node — 第五天

1. MySQL数据库 phpstudy 数据库服务器及图形化软件 软件链接 链接&#xff1a;https://pan.baidu.com/s/1F8wdoMstHAJkINfDKDejsw 提取码&#xff1a;xl3k 数据库对于我们前端同学来说&#xff0c;就是一个了解。 对于不会变化的数据&#xff08;省、市、县&#xff09;&…

iOS10 权限访问崩溃

手机升级了 iOS10 Beta&#xff0c;然后用正在开发的项目 装了个ipa包&#xff0c;发现点击有关 权限访问 直接Crash了&#xff0c;并在控制台输出了一些信息&#xff1a; This app has crashed because it attempted to access privacy-sensitive data without a usage descr…

Node — 第六天(前后端分离)及(身份验证)

综合应用服务端知识点搭建项目 下载安装所需的第三方模块 npm init -y npm i express cors mysql # express 用于搭建服务器 # cors 用于解决跨域 # mysql 用于操作数据库# 后面用到什么&#xff0c;再下载创建app.js 之前&#xff0c;我们开启一个服务器&#xff0c;js文件…

继承上机作业

1、实现如下类之间的继承关系&#xff0c;并编写Music类来测试这些类 2、编写一个Java应用程序&#xff0c;该程序包括3个类&#xff1a;Monkey类、People类和主类E。要求&#xff1a; (1) Monkey类中有个构造方法&#xff1a;Monkey (String s)&#xff0c;并且有个public voi…

ApplePay集成教程

Apple Pay运行环境&#xff1a;iPhone6以上设备&#xff0c;操作系统最低iOS9.0以上&#xff0c;部分信息设置需要iOS9.2以上。目前还不支持企业证书添加。 环境搭建好后可以在模拟器上面运行&#xff0c;xcode7.2.1iPhone6SP9.2系统下&#xff0c;系统会绑定几种虚拟的银行卡…

Node — 第七天 (大事件项目接口实现一)

关于JS错误处理 node中和mysql中的错误处理 node和MySQL提供的方法&#xff0c;已经对错误信息进行了封装&#xff0c;只需要使用 err.message 即可获取到错误信息。 比如&#xff1a; const fs require(fs); // 读取一个不存在的文件 fs.readFile(abcd.txt, (err, data) …

1.Consul 简介和环境搭建

1.什么是 Consul Consul 是 service mesh(服务网格)的一个解决方案&#xff0c;它提供了诸如服务发现&#xff0c;配置和隔离等功能的一整套控制平面(control plane)。开发人员可以根据需要单独使用这些功能点&#xff0c;也可以将他们整合成为一个完整的service mesh。Consul …

Node — 第八天 (大事件项目接口实现二)

如何处理MySQL的错误 MySQL的错误信息&#xff0c;可以通过err来获取。这是没有问题的。 但是&#xff0c;我们加入了Promise&#xff0c;Promise中的错误&#xff0c;在外部是获取不到的&#xff0c;只能使用Promise相关方法来获取错误信息。 解决方法一 使用 JS原生的 tr…

在local模式下的spark程序打包到集群上运行

一、前期准备 前期的环境准备&#xff0c;在Linux系统下要有Hadoop系统&#xff0c;spark伪分布式或者分布式&#xff0c;具体的教程可以查阅我的这两篇博客&#xff1a; Hadoop2.0伪分布式平台环境搭建 Spark2.4.0伪分布式环境搭建 然后在spark伪分布式的环境下必须出现如下八…

APS系统对制造企业到底有多重要?看完这5点你就明白了

第一个问题&#xff1a;需要APS吗&#xff1f; APS是否重要&#xff0c;不能从其所体现的软件工具或系统角度来说&#xff0c;而应该从业务角度来说。对于制造工厂和车间的运行而言&#xff0c;计划是核心的业务。就如同那句俗话说的&#xff0c;没有规矩不成方圆&#xff0c;领…

Node — 第九天 (大事件项目接口实现三)

文章管理接口 设计数据表 添加文章接口 编写接口&#xff0c;使用postman模拟提交formdata类型的数据 在article.js 中&#xff0c;加入 /add 路由 postman模拟提交formdata类型的数据 multer处理文件上传 下载安装multer 加载模块 const multer require(multer) 配置上…

Node — 第九天 (ES6降级 and 发布属于自己的[第三方模块]包)

ES6降级处理 因为 ES 6 有浏览器兼容性问题&#xff0c;可以使用一些工具进行降级处理&#xff0c;例如&#xff1a;babel 降级处理 babel 的使用步骤 安装 Node.js命令行中安装 babel配置文件 .babelrc运行命令&#xff0c;完成降级 项目初始化 (项目文件夹不能有中文) npm …

Vue — 第一天(极速入门)

基本介绍 vue是什么 目标&#xff1a;了解vue的一些基础概念。 官方网站&#xff1a; https://cn.vuejs.org/ vue是&#xff1a;渐进式javascript框架。 两组概念 &#xff08;1&#xff09;框架 库。只提供一些API给开发者使用。jquery 是一个js库框架。拥有自己的规则和…

Vue — 第二天(v-model和过滤器)

VUE-02-v-model和过滤器 昨日反馈与回顾 代码仓库的问题 不要修改你克隆下来的仓库中任意代码&#xff0c;否则&#xff0c;下次pull时&#xff0c;可能会报错&#xff0c;从而得到不到最新的代码。 如果已经遇到了这个冲突&#xff1a; 解决冲突(git 中解决冲突)把关键代码…

牛人iOS开发系列--音频播放、录音、视频播放、拍照、视频录制

概览 随着移动互联网的发展&#xff0c;如今的手机早已不是打电话、发短信那么简单了&#xff0c;播放音乐、视频、录音、拍照等都是很常用的功能。在iOS中对于多媒体的支持是非常强大的&#xff0c;无论是音视频播放、录制&#xff0c;还是对麦克风、摄像头的操作都提供了多套…

Vue — 第三天(计算属性和json-server)

计算属性 使用场景 如果一个结果需要依赖data中的数据&#xff0c;但是需要经过一些逻辑处理&#xff0c;才能得到你想要的数据。此时就可以使用计算属性。 例如&#xff1a;要对给定的字符串做翻转处理之后再来显示。 <div id"app"><!-- 此处逻辑复杂 …

Vue — 第四天(components组件)

问题导入 下面的代码是一个折叠面板的效果。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Docu…

iOS开发常用的RGB色值和宏

iOS中RGB常用的色值,同时可将对颜色的设置定义成宏,方便开发应用,如: // name 颜色相关 // 参数格式为&#xff1a;0xFFFFFF #define kColorWithRGB(rgbValue) \ [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16)) / 255.0 \ …

防火墙综合实验

防火墙技术综合实验 一、实验目的&#xff1a;本次实验是将多种访问控制列表以及防火墙部分的知识做一个汇总 二、实验内容 A&#xff1a;Established控制列表 拓扑图 配置步骤 1:配置各端口ip地址&#xff0c;配置登陆密码 R4: 登陆账号&#xff1a;ys 密码&#xff1a;123 2:…