回调地狱挖坑 - Promise
一、promise()
promise方法是专门用于解决异步回调问题的方法,在ES6和ES7语法中得到使用,promise实例对象中可以传回调函数,此函数有两个参数:resolve和rejects,如果一步操作成功,则通过resolve把数据传出去,如果失败,则通过rejdects把错误信息传出去
Tips:
1.promise函数必须通过then来获取数据
resolve函数的作用是,将promise对象的状态从“pending”变为‘’resolved‘’,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去
reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去
Promise构造的实例中可以传入一个回调函数,可以在这个回调函数里面执行异步操作,异步操作返回的结果通过resolve和reject传递出去,返回的是一个Promise对象,返回的参数需要该对象通过then函数获取到
下面我们演示一下:
我们通过计时器模拟异步加载来执行一些函数,正常情况如下:
function Test() {
setTimeout(function () {
let name = "测试"
return name
},1000)
}
function Test2() {
let name = Test()
console.log(name) => // undefined
}
Test2()
Test()里面执行了一个异步操作,正常Test2()执行时,Test的数据还没有返回,所以name是undefined
使用Promise()来执行一下看下结果:
let Eat = new Promise(resolve => {
setTimeout(function () {
let name = "测试"
resolve(name)
}, 1000)
})
function Test2() {
Eat.then(res => {
console.log(res) => // 测试
})
}
Test2()
可以看出Promise会等异步操作完成后,才会执行下一步操作
现在总体测试一下:
function first () {
setTimeout(function () {
console.log('这是第一步操作')
},4000)
}
function second () {
setTimeout(function () {
console.log('这是第二步操作')
},3000)
}
function third () {
setTimeout(function () {
console.log('这是第三步操作')
},2000)
}
function fourth () {
setTimeout(function () {
console.log('这是第四步操作')
},1000)
}
first()
second()
third()
fourth()
// 输出结果
这是第四步操作
这是第三步操作
这是第二步操作
这是第一步操作
看同步操作,即使first先执行,但是结果却是最后打印,fourth是最后执行,但结果却是最先打印
现在来看看改成promise后的结果:
function first () {
return new Promise(resolve => {
setTimeout(function () {
resolve('这是第一步操作')
},4000)
})
}
function second () {
return new Promise(resolve => {
setTimeout(function () {
resolve('这是第二步操作')
},3000)
})
}
function third () {
return new Promise(resolve => {
setTimeout(function () {
resolve('这是第三步操作')
},2000)
})
}
function fourth () {
return new Promise(resolve => {
setTimeout(function () {
resolve('这是第四步操作')
},1000)
})
}
first()
.then(res => {
console.log(res)
return second()
})
.then(res => {
console.log(res)
return third()
})
.then(res => {
console.log(res)
return fourth()
})
.then(res => {
console.log(res)
})
输出结果:
二、Promise方法
resolve() => // 传递异步成功时的数据
reject() => // 传递异步错误时的数据
then() => // 返回异步成功的数据作为参数
catch() => // 返回异步错误时的数据作为参数
function Test() {
let promise = new Promise({
if (success) {
resolve(success)
} else {
reject(err)
}
})
return promise
}
Test()
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
all
Promise的all方法提供了一个能够同时并行处理所以异步操作函数的能力,更加精简了代码,并且在所有异步操作执行完后才执行then回调,我们再次执行上面四个函数试试:
Promise
.all([first(),second(),third(),fourth()])
.then(res => {
console.log(res)
})
结果展示:
从上面执行结果来看,all方法接收一个数组参数,数组里面的值都是返回的Promise对象,到了then方法里面,all方法会把所有异步操作resolve的结果保存在一个数组里传给then
race
all方法是谁返回结果最慢,就先执行谁,而race确恰恰相反,race方法是谁返回结果最快,我就先执行谁,至于执行的表达式跟all方法完全没有区别
Promise
.race([first(),second(),third(),fourth()])
.then(res => {
console.log(res)
})
执行结果展示:
看到结果,感觉不对,只打印了执行最快的那个异步操作的resolve,并没有打印其他三个的数据,但事实上四个都已经执行了
个人理解回到all,是并行执行完成后执行then回调,而all是以最慢的执行为先,也就是其它快的相当于推迟几秒返回结果,其实是已经执行完了,然后一起完成执行then回调,而race是以最快的执行为先,一秒第四步就完成了,后面虽然执行了,但是then已经执行了,所以resolve也就没有作用了。