回调地狱的产生
无法保证顺序的代码:
var fs = require('fs')
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
// return console.log('读取失败')
// 抛出异常
// 1. 阻止程序的执行
// 2. 把错误消息打印到控制台
throw err
}
console.log(data)
})
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
})
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
})
由于是readFile是异步的,无法保证读取文件内容的输出是一步一步来的
如何保证顺序呢?通过回调的方式保证其顺序
var fs = require('fs')
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
})
})
})
这里只有三个异步函数,如果多个,会产生回调地狱。
一个任务依赖于一个异步任务执行完之后,这里必须进行嵌套才能解决。
问题:嵌套的太深,代码不好看,很难维护
怎么去解决这个问题呢?在ES6中新增了一个API——Promise
Promise是如何解决回调地狱的
promise是一个容器,里面存放了一个正在执行的任务(pending:正在执行),这个任务执行结束后,可能有两个状态,resolved(完成)和 rejected(失败),状态只能是其中的一种
promoise的使用
promise是一个构造函数
//promise容器一旦创建,就开始执行里面的代码,容器里可以放置异步函数,但是promise本身不是异步的
//创建Promise容器,给别人一个承若:I Promise you
var p1 = new Promise(function(resolve,reject){
console.log('hello') //这里的代码不是异步的
fs.readFile('./data/a.txt','utf8',function(err,data){
if(err){
//承渃容器中的任务失败了,把容器的Pending状态变为 Rejected
//调用reject就相当于调用了then方法的第二个参数
reject(err)
}else{
//承渃容器中的任务成功了,把容器的Pending状态变为 Resolved
//调用resolve就相当于调用了then方法的第一个参数
resolve(data)
}
})
})
//p1就是那个承若,当p1成功了,然后then做指定的操作,then方法接收的第一个function就是容器中的resolved函数
p1
.then(function(data){
console.log(data)
},function(err){
console.log('读取文件失败了',err)
})
promise解决回调地狱问题示例
var p1 = new Promise(function(resolve,reject){
fs.readFile('./data/a.txt','utf8',function(err,data){
if(err){
reject(err)
}else{
resolve(data)
}
})
})
var p2 = new Promise(function(resolve,reject){
fs.readFile('./data/b.txt','utf8',function(err,data){
if(err){
reject(err)
}else{
resolve(data)
}
})
})
var p2 = new Promise(function(resolve,reject){
fs.readFile('./data/c.txt','utf8',function(err,data){
if(err){
reject(err)
}else{
resolve(data)
}
})
})
p1
.then(function (data) {
console.log(data)
//当p1读取成功的时候
//当前函数中的return的结果就可以在后面的then中function
//当你return 123 后面接接收到 123
// return 'hello' 后面就接收到 ’hello'
// 没有return后面收到的就是undefined
//上面那些return的数据没什么卵用
//真正有用的是:我们可以return一个promise对象
//当return一个Promise对象的时候,后续的then中的方法的第一个参数会作为p2的resolve
return p2
}, function (err) {
console.log('读取文件失败了', err)
})
.then(function (data) {
console.log(data)
return p3
})
.then(function (data) {
console.log(data)
console.log('end')
})
封装promise ——API
var fs = require('fs')
function pReadFile(filePath) {
return new Promise(function (resolve, reject) {
fs.readFile(filePath, 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
}
pReadFile('./data/a.txt')
.then(function (data) {
console.log(data)
return pReadFile('./data/b.txt')
})
.then(function (data) {
console.log(data)
return pReadFile('./data/c.txt')
})
.then(function (data) {
console.log(data)
})
简单封装Promise版本的ajax方法
function pGet(url){
return new Promise(function(resolve,reject){
var xhr = new XMLHttpRequest()
xhr.onLoad = function(){
resolve(xhr.responseText)
}
xhr.onerror = function(err){
reject(err)
}
xhr.open('get',url,true)
xhr.send()
})
}
pGet('http:127.0.0.1/user')
.then(function(data){
console.log(data)
return pGet('http://127.0.0.1/job')
})
.then(function(data){
console.log(data)
})