1. 回调函数
1.1 回调函数的目的
获取函数中异步操作的结果,则必须通过回调函数获取
1.2 回调函数本质
回调函数的本质就是拿一个函数当参数传递给异步方法.在这个异步函数的内部调用传进来的函数,并把所需要传递出去的数据作为这个函数的参数,这样数据就传递出去.
1.2.1 示例
function fn(callback){
setTimeout(()=>{
let data = '数据'
callback(data)
},1000)
}
fn((data)=>{
console.log(data);
})
说明:
该示例中fn函数体里面有一个异步操作(setTimeout),要想获得这个异步操作的结果,就传递一个函数作为fn函数的参数传递进去,fn函数用形参callback来接收该函数.在异步操作的内部,通过调用该callback(参数),其中callback的参数就是需要传递出去的数据.然后调用fn函数时候,其参数里面写一个函数,并在该函数的参数接收数据.
传递进入的函数就叫做回调函数
1.3 回调使用
场景:由于读取文件速度不一样,导致异步任务中读取出来的数据不能保证顺序.为了保证顺序,所以就在回调里面套用回调,这样便形成了回调地狱
比如:
let fs = require('fs')
//输出内容通过回调来保证顺序
fs.readFile('./data/a.txt', (err, data) => {
if (err) return console.log('读取失败')
console.log(data.toString())
fs.readFile('./data/b.txt', (err, data) => {
if (err) return console.log('读取失败')
console.log(data.toString())
fs.readFile('./data/c.txt', (err, data) => {
if (err) return console.log('读取失败')
console.log(data.toString())
})
})
})
为了解决回调地狱,所以引入Promise
2. Promise
- Promise说明:Promise是一个容器,Promise是立即执行的,但是往往里面放异步任务.
- Promise有两个状态:resolve(成功) reject(失败).通过resolve(data)和reject(err)向外抛出结果
2.1 示例
let fs = require('fs')
let p = new Promise((resolve,reject)=>{
//一个异步任务
fs.readFile('./data/a.txt',(err,data)=>{
if(err){
reject(err)//把容器的状态变为失败,返回err
}else{
resolve(data)//把容器状态改为成功,返回data
}
})
})
//使用
p.then((data)=>{
console.log(data.toString())
},(err)=>{
console.log('读取文件失败了'+err)
})
//then方法的第一个参数 对应的是 resolve(data)
// 第二个参数 对应的是 reject(err)
2.2 实际使用
let fs = require('fs')
let p1 = new Promise((resolve, reject) => {
fs.readFile('./data/a.txt', (err, data) => {
if (err) reject(err)
else resolve(data)
})
})
let p2 = new Promise((resolve, reject) => {
fs.readFile('./data/b.txt', (err, data) => {
if (err) reject(err)
else resolve(data)
})
})
let p3 = new Promise((resolve, reject) => {
fs.readFile('./data/c.txt', (err, data) => {
if (err) reject(err)
else resolve(data)
})
})
p1.then((data) => {
console.log(data.toString())
return p2
}, (err) => {
console.log('读取文件失败了' + err)
})
.then((data) => {
console.log(data.toString())
return p3
}, (err) => {
console.log('读取文件失败了' + err)
})
.then((data) => {
console.log(data.toString())
}, (err) => {
console.log('读取文件失败了' + err)
})
通过then方法里成功调向外抛出Promise实例来实现链式调用
2.3 封装一下
let fs = require('fs')
let filePath1 = './data/a.txt'
let filePath2 = './data/b.txt'
let filePath3 = './data/c.txt'
function readFile(filePath) {
return new Promise((resolve, reject) => {
fs.readFile(filePath, (err, data) => {
if (err) reject(err)
else resolve(data)
})
})
}
//使用
readFile(filePath1).then(data => {
console.log(data.toString())
return readFile(filePath2)
}, err => {
console.log('读取文件失败' + err)
})
.then(data => {
console.log(data.toString())
return readFile(filePath3)
}, err => {
console.log('读取文件失败' + err)
})
.then(data => {
console.log(data.toString())
}, err => {
console.log('读取文件失败' + err)
})
2.4 链式调用
还有一种场景,需要对数据进行链式处理
new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('数据')
},1000)
}).then(data=>{
//继续处理
//return Promise.resolve(data+'111')
return data+'111'
}).thenn(data=>{
//继续处理
//return Promise.resolve(data+'222')
return data+'222'
})thenn(data=>{
//处理
})
2.5 all方法
场景:当需要两个异步请求同时获得时,才能进行下一个操作
Promise.all([
new Promise((resolve,reject)=>{
$ajax({
url:'',
success:(data)=>{
console.log('结果1'+data)
}
})
}),
new Promise((resolve,reject)=>{
$ajax({
url:'',
success:(data)=>{
console.log('结果2'+data)
}
})
})
]).then((data)=>{
//data是一个数据,一次保存上面Promise里抛出的值
console.log(data[0])
console.log(data[1])
})