1.回调地狱callback hell
由于异步操作是不能保证顺序的,但是有些异步操作之间是具有一定的关联性的,因此采用不断嵌套的方式保证顺序,但是嵌套越多代码可维护性越差,可读性越差。解决方法:promise
(es6新增的API)
2.promise语法
promise
是一个容器,里面存放的是异步操作,当执行异步操作的时候,promise状态为pending(未完成、正在执行)
,当异步操作完成之后,改变状态为resolve,reject
其中一种,其中resolve
为成功,reject
为失败,状态不可逆。切记:promise本身不是异步的,其里面的异步操作是异步的
const fs = require('fs');
// API
console.log('1');
// 创建异步容器new Promise
const p1 = new Promise(function (resolve,reject) {
console.log('2');
// 异步操作
fs.readFile('./data.txt',(err,data) => {
console.log('3');
if (err) {
// 改变promise状态为:reject
reject(err);
} else {
// 改变promise状态为resolve
resolve(data);
}
})
})
console.log('4'); // 最后打印结果为:1 2 4 3原因:promise本身不是异步的,其内的异步操作是异步的
/** then是异步操作完成之后执行的函数
第一个参数:resolve状态下执行的函数
第二个参数:reject状态下执行的函数
**/
p1.then(function (data) {
console.log(data.toString());
},function (err) {
console.log('err');
})
从以上语法可以分析出:promise的实现原理采取的是回调函数的方式,在异步操作中使用传递过去的函数。那如何解决回调地狱,使得代码可读性更高呢?通过then的链式调用
const fs = require('fs');
// API
const p1 = new Promise(function (resolve,reject) {
fs.readFile('./data.txt',(err,data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
})
})
const p2 = new Promise(function (resolve, reject) {
fs.readFile('./views/add.html',(err, data) => {
if (err) {
reject(err);
}
resolve(data);
})
})
p1
.then(function (data) {
console.log(data.toString());
return p2; // 返回promise容器实例
},function (err) {
console.log('err');
})
.then(function (data) { // 作为p2的异步操作完成之后的处理 // 按照之前的then中返回的数据进行顺序处理
console.log(data.toString());
return 123;// 还可以返回任意数据
})
.then(function(data) {
console.log(data);// 123 接收返回的数据
})
理解以上行为:由于then的链接调用保证了拿到数据时的顺序,采取promise包裹函数的方式,将异步操作进行封装,使多个异步任务异步执行,在then的链式调用中通过return promise实例
的方式保证获取到数据的顺序,采取这样的方式代码的可读性更高。