一、回调地狱?
要想明白Promise,我就要先了解一下什么是回调地狱?(若了解,请直接跳到下一节) 异步函数无法保证执行循序
const fs = require('fs')
fs.readFile('./data/a.txt', 'utf-8', (err, data) => {
if (err) {
console.log('读取失败');
}
console.log(data);
})
fs.readFile('./data/b.txt', 'utf-8', (err, data) => {
if (err) {
console.log('读取失败');
}
console.log(data);
})
fs.readFile('./data/c.txt', 'utf-8', (err, data) => {
if (err) {
console.log('读取失败');
}
console.log(data);
})
我们上面案例可以看出,我总共执行了三次回调地狱.js 这个js文件,前两次的执行循序是aaa bbb ccc,而到第三次却成了aaa ccc bbb 因此可以说明,Js的异步函数是无法保证执行循序的
可是有些时候,我们需要这些异步函数的执行循序是一定的 我们可以读取完a文件,控制台打印了a文件的data结果后,再去读取b文件,控制台打印…直到打印了c文件的data内容:
const fs = require('fs')
fs.readFile('./data/a.txt', 'utf-8', (err, data) => {
if (err) {
console.log('读取失败');
}
console.log(data);
fs.readFile('./data/b.txt', 'utf-8', (err, data) => {
if (err) {
console.log('读取失败');
}
console.log(data);
fs.readFile('./data/c.txt', 'utf-8', (err, data) => {
if (err) {
console.log('读取失败');
}
console.log(data);
})
})
})
经过这样的嵌套之嵌套之再嵌套,我们就能够得到稳定执行结果了。可是执行顺序是确定了,但是这样的代码嵌套地很深,不方便我们程序员后期维护。什么? 你觉得这还好,能看懂 那你瞧瞧这个呢? 是不是很恶心… = =
二、Promise
那如果我们不想用这种深层嵌套的方法,同时还想让异步函数有序地执行,还能有其他办法吗? 当然!ES6为我们提供了一个叫Promise接口,它专门用于解决回调地狱此类情况!
顾名思义,Promise 的中文意思为“承诺” ,我们在过往的生活中应该都有对他人的承诺的场景,比如:你向你的女朋友承诺:在她XX岁时,我要为咱们举办一场浪漫的婚礼。 而当你向女友做出“举办婚礼”的承诺时,你当下目前的状态 就是:正在加班努力实现承诺中(pending);而在未来 ,却只有两种可能(状态):1.成功了(resolve)???2.失败了(reject) 所以得出结论:pending状态只能转变为resolve或者reject其中一种状态。
那么,Promise到底是个什么?它又是怎样解决回调地狱的?
- Promise本质上是一个构造函数
- Promise实例的对象叫做‘Promise实例,可用来得到Promise内部成功或失败的结果
不明白很正常,请看下面例子:
const fs = require('fs')
new Promise(function(resolve,reject) {
fs.readFile('./data/a.txt','utf-8',(err,data) => {
if(err) {
reject(err)
}
resolve(data)
})
})
从以上代码可以看出,在new完Promise后,会向这个构造函数传入一个函数作为参数,而这个函数内部,就是你的异步代码,这样看来,Promise就像一个容器一样包裹着你的异步函数。
const fs = require('fs')
let p1 = new Promise(function(resolve,reject) {
fs.readFile('./data/a.txt','utf-8',(err,data) => {
if(err) {
reject(err)
}
resolve(data)
})
})
p1.then(function(data){
console.log(data);
})
我们可以看到,Promise实例了p1,p1又调用了身上的then函数,而这个then函数里面这个参数函数,就是Promise内部resolve这个函数。 因此也就在外部拿到data值了。
三、Promise解决回调地狱
在上面案例中,我们了解到Promise的基本使用,接下来我们就来用Promise解决回调地狱
const fs = require('fs')
const p1 = new Promise(function(resolve,reject) {
fs.readFile('./data/a.txt','utf-8',(err,data) => {
if(err) {
console.log('读取失败');
reject(err)
}
resolve(data)
})
})
const p2 = new Promise(function(resolve,reject) {
fs.readFile('./data/b.txt','utf-8',(err,data) => {
if(err) {
reject(err)
}
resolve(data)
})
})
const p3 = new Promise(function(resolve,reject) {
fs.readFile('./data/c.txt','utf-8',(err,data) => {
if(err) {
reject(err)
}
resolve(data)
})
})
p1.then(function(data) {
console.log(data);
return p2
}).then(function(data) {
console.log(data);
return p3
}).then(function(data) {
console.log(data);
})
以上代码虽然有点长,但是慢慢看完你一定会明白。 因为在p1.then函数中,其内部函数参数又return p2这个Promise,那么在下一部分的.then中这个函数参数就是上一个Promise的resolve函数,听起来很绕对吧,我们看下图就能明白: 因为我们就成功有序拿到了data。 这就称为Promise的链式调用,解决了回调地狱。
|