Node.js Promise对象(解决回调地狱问题)async和await函数
Posted YuLong~W
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node.js Promise对象(解决回调地狱问题)async和await函数相关的知识,希望对你有一定的参考价值。
回调函数及异步任务
回调函数:
当一个函数作为参数传入另一个参数中,并且它不会立即执行,只有当满足一定条件后该函数才可以执行,这种函数就称为回调函数
异步任务:
与之相对应的概念是“同步任务”,同步任务在主线程上排队执行,只有前一个任务执行完毕,才能执行下一个任务。异步任务不进入主线程,而是进入异步队列,前一个任务是否执行完毕不影响下一个任务的执行
setTimeout(function () {
console.log('执行了回调函数');
},1000)
console.log('程序结束')
//输出结果是:
//程序结束
//执行了回调函数
这种不阻塞后面任务执行的任务就叫做异步任务
回调地狱
实例1: 打印一句话,语序必须是:”武林要以和为贵,要讲武德,不要窝里斗。”
//回调函数的实现
setTimeout(function () {
console.log('武林要以和为贵');
setTimeout(function () {
console.log('要讲武德');
setTimeout(function () {
console.log('不要窝里斗');
},1000)
},2000)
},3000)
- 这种回调函数中嵌套回调函数的情况就叫做 回调地狱
- 回调地狱就是为实现代码顺序执行而出现的一种操作
回调地狱问题:
- 嵌套层次很深,可读性差,难以维护
- 无法正常使用 return 和 throw
- 无法正常检索堆栈信息
- 多个回调之间难以建立联系
Promise对象
Promise对象 是js中的一个原生对象,是一种异步编程的解决方案,可以替换掉传统的回调函数解决方案
ES6中,Promise通过引入一个回调,避免更多的回调,简单说Promise就是一个容器,里面保存着某个未来才会结束的事件 (通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。
//promise对象实现
function fn(str) {
//创建promise对象
var p=new Promise(function (resolve, reject) {
let flag=true;
setTimeout(function () {
if (flag){
resolve(str);//回调成功
}else{
reject('操作失败');
}
})
})
return p;
}
fn('武林要以和为贵').then(d1=>{ //参数d1存放的是promise对象回调成功resolve的信息
console.log(d1);
return fn('要讲武德');
}).then(d2=>{
console.log(d2);
return fn('不要窝里斗');
}).then(d3=>{
console.log(d3);
}).catch(err=>{
console.log(err);
})
Promise有3个状态:
- 1.pending[待定] :初始状态,没有实现也没有被拒绝。
- 2.resloved[实现] :操作成功
- 3.rejected[被拒绝] :操作失败
Promise对象状态:
- Promise 状态发生改变,就会触发.then() 里的响应函数处理后续步骤
- Promise 状态一经改变,不会再变
- Promise 实例一经创建,执行器立即执行
Promise详解:
- 1、Promise构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject ,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。它们是两个函数,又是javascript引擎提供,不是自己部署
- resolve函数的作用:将Promise对象的状态从 “未完成” 变成 “成功” (即从Pending变为Resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去
- reject函数的作用是:在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去
- 2、Promise对象的 then方法 用来接收处理成功时响应的数据,catch方法 用来接收处理失败时相应的数据
- 3、Promise的链式编程可以保证代码的执行顺序,前提是每一次在then做完处理后,一定要return一个Promise对象,这样才能在下一次then时接收到数据。
Promise的使用
创建Promise对象:
let promise = new Promise((resolve, reject) => {
//执行异步操作代码
if (/*成功 */) {
resolve(value); //异步操作执行成功后的回调函数
}else {
reject(error); //异步操作执行失败后的回调函数
});
then():
promise.then((value) => { //成功
console.log('成功',value);
},(error) => { //失败
console.err('失败',error);
})
catch():
promise.then((value) => {
console.log('成功',value);
}).catch((error) => {
console.err('失败',error);
})
Promise.resolve()
Promise.reject()
Promise.all():
- Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调
- 用Promise.all来执行,all接收一个数组参数,里面的值最终都返回Promise对象
- Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值
- 需要特别注意的是:Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2要晚
- 这样最大的好处是:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题
var promise1 = Promise.resolve(70);
var promise2 = 82;
var promise3 = new Promise(function(resolve) {
setTimeout(resolve,1000,95); //1秒钟之后执行
});
Promise.all([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});// 输出数组: [ 70, 82, 95 ]
Promise.race():
var promise1 = Promise.resolve(70);
var promise2 = 82;
var promise3 = new Promise(function(resolve) {
setTimeout(resolve,1000,95); //1秒钟之后执行
});
Promise.race([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});// 输出数组: [ 70]
- Promse.race就是赛跑的意思,意思就是说,Promise.race([p1,p2,p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态
结论:
Promise虽然跳出了异步嵌套的怪圈,用链式表达更加清晰,但是如果有大量的异步请求的时候,流程复杂的情况下,会发现充满了屏幕的then,而 ES7的 async/await 的出现就是为了解决这种复杂的情况
async/await函数
//async/await的实现
async function test() {
let str1=await fn('武林要以和为贵');
let str2=await fn('要讲武德');
let str3=await fn('不要窝里斗');
console.log(str1,str2,str3);
}
异步函数: 是异步编程语法的终极解决方案,它可以让异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了
async 关键字:
- 普通函数定义前加 async 关键字 普通函数变成异步函数
- 异步函数默认返回 promise对象
- 在异步函数内部使用 return关键字进行结果返回 。结果会被包裹的promise对象中 return 关键字代替 resolve方法
- 在异步函数内部使用throw 关键字抛出程序异常
- 调用异步函数再链式调用then方法、catch方法分别获取异步函数执行结果和错误信息
await关键字:
- await关键字只能出现在异步函数中
- await promise :await后面只能写promise对象 写其他类型的API是不不可以的
- await关键字可以是暂停异步函数向下执行 ,直到promise返回结果
Promise和async/await区别:
- Promise是 ES6,async/await是 ES7
- async/await 相对于 Promise来讲,写法更加优雅
- reject状态:
- promise错误可以通过catch来捕捉,建议尾部捕获错误
- async/await既可以用 .then 又可以用 try-catch 捕捉
async/await的特点:
- async/await 从上到下顺序执行,符合编写代码的习惯。 async/await可以传递的参数数量不受限制。
- 同步代码和异步代码可以一起编写,只是要注意异步过程需要包装成一个Promise对象并置于await关键字后面。
- async/await基于协程(Coroutine)的机制,是对异步过程更精确的一种描述。
- async/await是对Promise的改进。只是语法糖,本质上仍然是Promise。
async函数的语法格式:
async function name([param[, param[, ... param]]]) { statements }
function resolveAfter1Seconds() { //将异步过程包装为Promise
return new Promise(resolve => {
setTimeout(() => {
resolve('已成功');
}, 1000);
});
}
async function asyncFunc() { //定义async函数
console.log('正在执行async函数');
var result = await resolveAfter1Seconds(); // await表达式
console.log(result); // 输出'已成功'
}
asyncFunc(); //调用async函数
console.log('async函数代码开始执行');
以上是关于Node.js Promise对象(解决回调地狱问题)async和await函数的主要内容,如果未能解决你的问题,请参考以下文章
最近在找前端工作,然后面试的时候人家问我。promise为啥能解决地狱回调,为啥能一直.then?
利用async和await异步操作解决node.js里面fs模块异步读写,同步结果的问题