什么是Promise
Promise 是一個(gè)對(duì)象彼乌,對(duì)象里存儲(chǔ)一個(gè)狀態(tài)膨蛮,這個(gè)狀態(tài)是可以隨著內(nèi)部的執(zhí)行轉(zhuǎn)化的滋尉,為以下三種狀態(tài)之一:等待態(tài)(Pending)、完成態(tài)(Fulfilled)疲吸、拒絕態(tài)(Rejected)座每。
一開始,我們先設(shè)置好等狀態(tài)從 pending 變成 fulfilled 和 rejected 的預(yù)案(當(dāng)成功后我們做什么摘悴,失敗時(shí)我們做什么)峭梳。
Promise 啟動(dòng)之后,當(dāng)滿足成功的條件時(shí)我們讓狀態(tài)從 pending 變成 fullfilled (執(zhí)行 resolve)蹂喻;當(dāng)滿足失敗的條件葱椭,我們讓狀態(tài)從 pending 變成 rejected(執(zhí)行 reject)
Promise范例
范例1
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('出現(xiàn)了錯(cuò)誤', e)
})
Promise.all
范例2
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, 當(dāng)所有的 Promise 對(duì)象都完成后再執(zhí)行
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.all, 當(dāng)所有的 Promise 對(duì)象都完成后再執(zhí)行
Promise.race([p1, p2, p3]).then(data=>{
console.log(data)
})
對(duì)于回調(diào)地獄的解決
function fn1() {
setTimeout(()=>{
console.log('fn1')
}, 1000)
}
function fn2() {
setTimeout(()=>{
console.log('fn2')
}, 1000)
}
function fn3() {
setTimeout(()=>{
console.log('fn3')
}, 1000)
}
對(duì)于以上代碼如何實(shí)現(xiàn): 1秒鐘之后輸出 fn1, 再過疫苗輸出 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()
})
})
回調(diào)地獄
*我們可以利用Promise進(jìn)行改寫*
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對(duì)ajax進(jìn)行改造
改造前
function ajax(opts){
var url = opts.url
var type = opts.type || 'GET'
var dataType = opts.dataType || 'json'
var onsuccess = opts.onsuccess || function(){}
var onerror = opts.onerror || function(){}
var data = opts.data || {}
var dataStr = []
for(var key in data){
dataStr.push(key + '=' + data[key])
}
dataStr = dataStr.join('&')
if(type === 'GET'){
url += '?' + dataStr
}
var xhr = new XMLHttpRequest()
xhr.open(type, url, true)
xhr.onload = function(){
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
//成功了
if(dataType === 'json'){
onsuccess( JSON.parse(xhr.responseText))
}else{
onsuccess( xhr.responseText)
}
} else {
onerror()
}
}
xhr.onerror = onerror
if(type === 'POST'){
xhr.send(dataStr)
}else{
xhr.send()
}
}
ajax({
url: 'http://api.jirengu.com/weather.php',
data: {
city: '北京'
},
onsuccess: function(ret){
console.log(ret)
},
onerror: function(){
console.log('服務(wù)器異常')
}
})
改造后
function ajax(opts){
var url = opts.url
var type = opts.type || 'GET'
var dataType = opts.dataType || 'json'
var data = opts.data || {}
var dataStr = []
for(var key in data){
dataStr.push(key + '=' + data[key])
}
dataStr = dataStr.join('&')
if(type === 'GET'){
url += '?' + dataStr
}
var promise = new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest()
xhr.open(type, url, true)
xhr.onload = function(){
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
//成功了
if(dataType === 'json'){
resolve( JSON.parse(xhr.responseText))
}else{
resolve( xhr.responseText)
}
} else {
reject()
}
}
xhr.onerror = reject()
if(type === 'POST'){
xhr.send(dataStr)
}else{
xhr.send()
}
})
return promise
}
ajax({
url: 'http://api.jirengu.com/weather.php',
data: {
city: '北京'
}
}).then(function(ret){
console.log(ret)
}).catch(function(){
console.log('服務(wù)器異常')
})