express
一、CommonJs
-
JavaScript 是一个强大面向对象语言,它有很多快速高效的解释器。然而, JavaScript标准定义的 API 是为了构建基于浏览器的应用程序。并没有制定一个用于更广泛的应用程序的标准库。
-
CommonJS 规范的提出,主要是为了弥补当前 JavaScript 没有标准库的缺陷。它的终极目标就是:提供一个类似 Python,Ruby 和 Java 语言的标准库,而不只是让 JavaScript 停留在小脚本程序的阶段。用 CommonJS API 编写出的应用,不仅可以利用 JavaScript 开发客户端应用,而且还可以编写以下应用。
1. 服务器端 JavaScript 应用程序。(nodejs)
2. 命令行工具。
3. 桌面图形界面应用程序。 -
CommonJS 就是模块化的标准,nodejs 就是 CommonJS(模块化)的实现。
二、Promise
2.1 回调地狱
由多层嵌套的回调函数组成的代码称为回调地狱,多数在写阻塞执行代码的时候会产生。回调地狱的代码可读性差,很难让人弄清楚业务逻辑。
function callbackFn(callback){
setTimeout(function(){
callback()
},1000)
}
callbackFn(function(){
callbackFn(function(){
callbackFn(function(){
callbackFn(function(){console.log('回调结束')})
})
})
})
上面的代码执行4秒后会输出’回调结束‘,虽然达到了我们要阻塞执行的目的,但是非常不容易让人读懂,且书写麻烦
2.2 promise是什么
2.2.1 抽象表达
- Promise是一门新的技术(ES6规范)
- Promise是JS中进行异步编程的新解决方案
备注:旧方案是单纯使用回调函数
2.2.2 具体表达
- 从语法上来说: Promise是一个构造函数
- 从功能上来说: Promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
2.2.3 Promise有三个状态
- Pending:异步的事情正在执行;
- Fulfilled:异步的事情成功了;
- Rejected:异步的事情失败了
2.2.4 promise的状态改变
- pending变为resolved
- pending变为rejected
说明: 只有这2种, 且一个promise对象只能改变一次无论变为成功还是失败, 都会有一个结果数据,成功的结果数据一般称为value, 失败的结果数据一般称为reason
2.3 promise基本流程
2.4 promise的优势
2.4.1. 指定回调函数的方式更加灵活
- 旧的: 必须在启动异步任务前指定
- promise: 启动异步任务=> 返回promie对象=> 给promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个)
2.4.2 支持链式调用, 可以解决回调地狱问题
- 什么是回调地狱?
回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件 - 回调地狱的缺点?
不便于阅读,不便于异常处理 - 解决方案?
promise链式调用 - 终极解决方案?
async/await
2.5 promise的使用:解决回调地狱问题
/*回调地狱*/
doSomething(function(result){
doSomethingElse(result,function(newResult){
doThirdThing(newResult,function(finalResult){
console.log('Gotthefinalresult:'+finalResult)
},failureCallback)
},failureCallback)
},failureCallback)
/*使用promise的链式调用解决回调地狱*/
doSomething().then(function(result){
return doSomethingElse(result)})
.then(function(newResult){
return doThirdThing(newResult)})
.then(function(finalResult){
console.log('Gotthefinalresult:'+finalResult)})
.catch(failureCallback)
function doDelay(time){
//1.创建promise对象
return new Promise((resolve,reject)=>{
//2.启动异步任务
console.log('启动异步任务') ;
setTimeout(()=>{
console.log('延迟任务开始执行...')
const time = Date.now()
//假设:时间为奇数代表成功,为偶数代表失败
if(time % 2 === 1){
//成功了
//3.1.如果成功了,调用resolve()并传入成功的value
resolve('成功的数据'+time)
}else{
//失败了
//3.2.如果失败了,调用reject()并传入失败的reason
reject('失败的数据'+time)
}},time)
})
}
const promise = doDelay(2000) ;
promise.then(value=>{
console.log('成功的value:',value)},
reason=>{
console.log('失败的reason:',reason)},)
2.6 async/await 同时使用
- async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async用于申明一个异步的 function ,而 await 用于等待一个异步方法执行完成。
- 简单理解:
async 是让方法变成异步。
await 是等待异步方法执行完成。 - 详细说明:
async 是让方法变成异步,在终端里用 node 执行这段代码,你会发现输出了Promise {‘Hello async’ }
,这时候会发现它返回的是 Promise。
async function testAsync(){
return 'Hello async';
}
const result = testAsync();
console.log(result);
- await 在等待 async 方法执行完毕,其实 await 等待的只是一个表达式,这个表达式在官方文档里说的是 Promise 对象,但是它也可以接受普通值。
- 注意:await 必须在 async 方法中才可以使用因为 await 访问本身就会造成程序停止堵塞,所以必须在异步方法中才可以使用
- async 会将其后的函数(函数表达式或 Lambda)的返回值封装成一个 Promise 对象,而await 会等待这个 Promise 完成,并将其 resolve 的结果返回出来。
2.7 Promise的使用
- API1.Promise构造函数:
Promise (excutor) {}
(1) executor函数: 执行器(resolve, reject) => {}
(2) resolve函数: 内部定义成功时我们调用的函数value => {}
(3) reject函数: 内部定义失败时我们调用的函数reason => {}
说明: executor会在Promise内部立即同步调用,异步操作在执行器中执行 - Promise.prototype.then方法:
(onResolved, onRejected) => {}
(1) onResolved函数: 成功的回调函数(value) => {}
(2) onRejected函数: 失败的回调函数(reason) => {}
说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调返回一个新的promise对象 - Promise.prototype.catch方法:
(onRejected) => {}
(1)onRejected函数: 失败的回调函数(reason) => {}
说明: then()的语法, 相当于:then(undefined, onRejected)
- Promise.resolve方法:
(value) => {}
(1) value: 成功的数据或promise对象
说明: 返回一个成功/失败的promise对象 - Promise.reject方法:
(reason) => {}
(1) reason: 失败的原因
说明: 返回一个失败的promise对象 - Promise.all方法:
(promises) => {}
(1) promises: 包含n个promise的数组
说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败 - Promise.race方法:
(promises) => {}
(1) promises: 包含n个promise的数组
说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态
2.8 Promise的几个关键问题
- 如何改变promise的状态?
(1) resolve(value): 如果当前是pending就会变为resolved
(2) reject(reason): 如果当前是pending就会变为rejected
(3) 抛出异常: 如果当前是pending就会变为rejected - 一个promise指定多个成功/失败回调函数, 都会调用吗?
当promise改变为对应状态时都会调用 - 改变promise状态和指定回调函数谁先谁后?
(1) 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
(2) 如何先改状态再指定回调?
①在执行器中直接调用resolve()/reject()
②延迟更长时间才调用then()
(3) 什么时候才能得到数据?
①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据 - promise.then()返回的新promise的结果状态由什么决定?
(1) 简单表达: 由then()指定的回调函数执行的结果决定
(2) 详细表达:
① 如果抛出异常, 新promise变为rejected, reason为抛出的异常
② 如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果 - promise如何串连多个操作任务?
(1) promise的then()返回一个新的promise, 可以开成then()的链式调用
(2) 通过then的链式调用串连多个同步/异步任务 - promise异常传透?
(1) 当使用promise的then链式调用时, 可以在最后指定失败的回调,
(2) 前面任何操作出了异常, 都会传到最后失败的回调中处理 - 中断promise链?
(1) 当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
(2) 办法: 在回调函数中返回一个pendding状态的promise对象