什么是回调地狱(callback hell)?
对于无法保证顺序的代码,我们采取回调函数的方式,但是这会导致一个问题,就是让我们的代码可读性和可维护性较差。例如:
var fs = require('fs');
//readFile是异步的,先输出谁的顺序没办法保证
//实现先输出a,再输出b,最后输出c
fs.readFile('./data/a.txt',function (err,data){
if(err){
// return console.log('读取失败');
//抛出异常
// 1、阻止程序运行
// 2、把错误消息打印到控制台
throw err;
}
console.log(data.toString());
fs.readFile('./data/b.txt','utf-8',function (err,data){
if(err){
throw err;
}
console.log(data);
fs.readFile('./data/c.txt',function (err,data){
if(err){
throw err;
}
console.log(data.toString());
})
})
})
为了解决以上编码方式带来的问题(回调地狱嵌套),所以在ES6中新增了一个API: Promise
。
- promise的英文就是承诺、保证的意思
基本语法+代码图示:
解决回调地狱:
var fs = require('fs');
//在 ES6 中新增了一个API Promise
//Promise是一个构造函数
//创建Promise容器
//1、给别人一个承诺 I promise you
// Promise 容器一旦创建,就开始执行里面的代码
// Promise本身不是异步,但是内部往往封装的是一个异步任务
// console.log(1);
var p1 = new Promise(function (resolve,reject){
// console.log(2);
fs.readFile('./data/a.txt','utf-8',function (err,data){
// console.log(3);
if(err){
// //承诺容器中的任务失败了
// console.log(err);
//把容器的 pending 状态改为 rejected
//调用reject 就相当于调用 then 里面的第二个参数
reject(err);
}else{
//承诺容器中的任务成功了
// console.log(data);
//把容器的 pending 状态改为 成功
resolve(data);
}
})
// console.log(4);
});
var p2 = new Promise(function (resolve,reject){
fs.readFile('./data/b.txt','utf-8',function (err,data){
if(err){
reject(err);
}else{
resolve(data);
}
})
});
var p3 = new Promise(function (resolve,reject){
fs.readFile('./data/c.txt','utf-8',function (err,data){
if(err){
reject(err);
}else{
resolve(data);
}
})
});
//p1就是那个承诺
//当 p1 成功了 然后(then) 做指定的操作
//then方法接收的第一个 function 就是容器中的 resolve 函数
// 第二个 function 就是容器中的 reject 函数
p1
.then(function (data){
console.log(data);
//当p1读取成功的时候
//当前函数中 return 的结果就可以在后面的 then 中 function 接收到
//当你 return 123,后面就接收到123
// return 'hello',后面就接收到’hello‘
//上面那些 return 的数据没有什么用
//真正有用的是 return 一个 Promise 对象
//当 return 一个Promise 对象的时候,后续的then 中的方法的第一个参数会作为 p2 的 resolve
return p2;
},function (err){
console.log('读取文件失败了')
})
.then(function (data){
console.log(data);
return p3;
})
.then(function (data){
console.log(data)
})
封装异步的 readFile之后:
var fs = require('fs');
function pReadFile(filePath,){
var p = new Promise(function (resolve,reject){
fs.readFile(filePath,'utf-8',function (err,data){
if(err){
reject(err);
}else{
resolve(data);
}
})
});
return p;
}
pReadFile('./data/a.txt')
.then(function (data){
console.log(data);
return pReadFile('./data/b.txt');
},function (err){
console.log('读取文件失败了')
})
.then(function (data){
console.log(data);
return pReadFile('./data/c.txt');
})
.then(function (data){
console.log(data)
})