我们先来看一个例子
function fn1() {
setTimeout(()=>{
console.log('fn1')
}, 1000)
}
function fn2() {
setTimeout(()=>{
console.log('fn2')
}, 1000)
}
function fn3() {
setTimeout(()=>{
console.log('fn3')
}, 1000)
}
以上代码,如何实现:1秒钟之后输出fn1,再过1秒输出fn2,再过1秒输出fn3?
可如下改装:
function fn1(callback) {
setTimeout(()=>{
console.log('fn1')
callback()
}, 1000)
}
function fn2(callback) {
setTimeout(()=>{
console.log('fn2')
callback()
}, 1000)
}
function fn3() {
setTimeout(()=>{
console.log('fn3')
}, 1000)
}
fn1(function(){
fn2(function(){
fn3()
})
})
这就是回调地狱!!!
什么是 Promise
Promise 是一个对象,对象里面存储了一个状态,这个状态是可以随着内部的执行转换为以下三种状态之一:等待(Pending)、完成(Fulfilled)、拒绝(Rejected)。
一开始,我们先设置好等待状态从 pending 变成 fulfilled 和 rejected 的预案。(即当成功时做什么,当失败时做什么)
Promise 启动之后,当满足成功的条件时,我们让状态从 pending 变成 fulfilled (执行resolve);当满足失败的条件时,我们让状态从 pending 变成 rejected (执行 reject)
Promise.prototype.then / Promise.prototype.catch
function getIp() {
var promise = new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest()
xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getIp', true)
xhr.onload = function(){
var retJson = JSON.parse(xhr.responseText) // {"ip":"58.100.211.137"}
resolve(retJson.ip)
}
xhr.onerror = function(){
reject('获取IP失败')
}
xhr.send()
})
return promise
}
function getCityFromIp(ip) {
var promise = new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest()
xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getCityFromIp?ip='+ip, true)
xhr.onload = function(){
var retJson = JSON.parse(xhr.responseText) // {"city": "hangzhou","ip": "23.45.12.34"}
resolve(retJson.city)
}
xhr.onerror = function(){
reject('获取city失败')
}
xhr.send()
})
return promise
}
function getWeatherFromCity(city) {
var promise = new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest()
xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getWeatherFromCity?city='+city, true)
xhr.onload = function(){
var retJson = JSON.parse(xhr.responseText) //{"weather": "晴天","city": "beijing"}
resolve(retJson)
}
xhr.onerror = function(){
reject('获取天气失败')
}
xhr.send()
})
return promise
}
getIp().then(function(ip){
return getCityFromIp(ip)
}).then(function(city){
return getWeatherFromCity(city)
}).then(function(data){
console.log(data)
}).catch(function(e){
console.log('出现了错误', e)
})
Promise.all
function getCityFromIp(ip) {
var promise = new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest()
xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getCityFromIp?ip='+ip, true)
xhr.onload = function(){
var retJson = JSON.parse(xhr.responseText) // {"city": "hangzhou","ip": "23.45.12.34"}
resolve(retJson)
}
xhr.onerror = function(){
reject('获取city失败')
}
xhr.send()
})
return promise
}
var p1 = getCityFromIp('10.10.10.1')
var p2 = getCityFromIp('10.10.10.2')
var p3 = getCityFromIp('10.10.10.3')
//Promise.all, 当所有的 Promise 对象都成功后再执行
Promise.all([p1, p2, p3]).then(data=>{
console.log(data)
})
Promise.race
function getCityFromIp(ip) {
var promise = new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest()
xhr.open('GET', 'https://easy-mock.com/mock/5ac2f80c3d211137b3f2843a/promise/getCityFromIp?ip='+ip, true)
xhr.onload = function(){
var retJson = JSON.parse(xhr.responseText) // {"city": "hangzhou","ip": "23.45.12.34"}
resolve(retJson)
}
xhr.onerror = function(){
reject('获取city失败')
}
setTimeout(()=>{
xhr.send()
}, Math.random()*1000)
})
return promise
}
var p1 = getCityFromIp('10.10.10.1')
var p2 = getCityFromIp('10.10.10.2')
var p3 = getCityFromIp('10.10.10.3')
//Promise.race, 是谁先成功就执行谁,比如p1先执行成功,那么then就执行p1返回的数据。
Promise.race([p1, p2, p3]).then(data=>{
console.log(data)
})
开头回调地狱的解决
function fn1() {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
console.log('fn1...')
resolve()
}, 1000)
})
}
function fn2() {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
console.log('fn2...')
resolve()
}, 1000)
})
}
function fn3() {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
console.log('fn3...')
resolve()
}, 1000)
})
}
function onerror() {
console.log('error')
}
fn1().then(fn2).then(fn3).catch(onerror)
总结
Promise.all是将多个Promise对象合并成一个新的Promise对象,并在所有Promise对象都成功时返回一个结果数组,或者在任意一个Promise对象失败时返回该Promise对象的错误信息。
Promise.race是将多个Promise对象合并成一个新的Promise对象,并在最快的Promise对象变为fulfilled或rejected状态时返回其结果或错误信息。
Promise.prototype.then用来处理成功的结果。
Promise.prototype.catch用来处理错误的结果。