中国企业库,苏州网站优化哪家好,一站式网站设计,大连短视频运营Promise - ES6新对象
Promise能够处理异步程序。
回调地狱 JS中或node中#xff0c;都大量的使用了回调函数进行异步操作#xff0c;而异步操作什么时候返回结果是不可控的#xff0c;如果我们希望几个异步请求按照顺序来执行#xff0c;那么就需要将这些异步操作嵌套起来…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 用于修饰一个 functionasync 修饰的函数表示该函数里面有异步操作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 上而是推荐将路由抽离为单独的模块。 将路由抽离为单独模块的步骤如下: 创建路由模块对应的 .js 文件 创建router/login.js 存放 登录、注册、验证码三个路由创建router/heroes.js 存放 和英雄相关的所有路由 调用 express.Router() 函数创建路由对象 const express require(express);
const router express.Router();向路由对象上挂载具体的路由 // 把app换成router比如
router.get(/xxx/xxx, (req, res) {});
router.post(/xxx/xxx, (req, res) {});使用 module.exports 向外共享路由对象 module.exports router;使用 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…