promise
。function requestData(url) {
setTimeout(() => {
if (url === 'iceweb.io') {
return '請求成功'
}
return '請求失敗'
}, 3000)
}
const result = requestData('iceweb.io')
console.log(result) //undefined
登入後複製
js
程式碼的執行順序,而不是是想當然的,程式碼其實並不是按照你書寫的順序執行的。undefined呢
?requestData
函數,開始執行函數。遇到了非同步操作不會阻塞後面程式碼執行的,因為js是單執行緒的,所以你寫的return
成功或者失敗並沒有返回,那我這個函數中,拋開非同步操作,裡面並沒有返回值,所以值為undefined
。function requestData(url, successCB, failureCB) {
setTimeout(() => {
if (url === 'iceweb.io') {
successCB('我成功了,把獲取到的資料傳出去', [{name:'ice', age:22}])
} else {
failureCB('url錯誤,請求失敗')
}
}, 3000)
}
//3s後 回撥successCB
//我成功了,把獲取到的資料傳出去 [ { name: 'ice', age: 22 } ]
requestData('iceweb.io', (res, data) => console.log(res, data), rej => console.log(rej))
//3s後回撥failureCB
//url錯誤,請求失敗
requestData('icexxx.io', res => console.log(res) ,rej => console.log(rej))
登入後複製
Promise
(承諾),給予呼叫者一個承諾,過一會返回資料給你,就可以建立一個promise物件new
一個promise
,此時我們需要傳遞一個回撥函數,這個函數為立即執行的,稱之為(executor)reslove
,reject
(函數可以進行傳參)reslove
函數,會回撥promise物件的.then函數reject
函數,會回撥promise物件的.catche函數new Promise((resolve, reject) => {
console.log(`executor 立即執行`)
})
登入後複製
executor
是立即執行的function requestData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url === 'iceweb.io') {
//只能傳遞一個引數
resolve('我成功了,把獲取到的資料傳出去')
} else {
reject('url錯誤,請求失敗')
}
}, 3000)
})
}
//1. 請求成功
requestData('iceweb.io').then(res => {
//我成功了,把獲取到的資料傳出去
console.log(res)
})
//2. 請求失敗
//2.2 第一種寫法
//url錯誤,請求失敗
requestData('iceweb.org').then(res => {},rej => console.log(rej))
//2.2 第二種寫法
//url錯誤,請求失敗
requestData('iceweb.org').catch(e => console.log(e))
登入後複製
executor
(會被Promise類中自動執行)resolve
函數,失敗的時候呼叫reject
函數,把需要的引數傳遞出去。.then
方法中可以傳入兩個回撥,您也可以檢視Promise/A+規範fulfilled
的回撥rejected
的回撥統一規範,可以增強閱讀性和擴充套件性
小幅度減少回撥地獄
promise
的時候,給它一個承諾,我們可以將他劃分為三個階段resolve
函數則代表了已兌現狀態reject
函數則代表了已拒絕狀態思考以下程式碼:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject('失敗')
resolve('成功')
}, 3000);
})
promise.then(res => console.log(res)).catch(err => console.log(err))
//失敗
登入後複製
reject
之後,在呼叫resolve
是無效的,因為狀態已經發生改變,並且是不可逆的。resolve
傳入一個普通的值或者物件,只能傳遞接受一個引數,那麼這個值會作為then
回撥的引數const promise = new Promise((resolve, reject) => {
resolve({name: 'ice', age: 22})
})
promise.then(res => console.log(res))
// {name: 'ice', age: 22}
登入後複製
resolve
中傳入的是另外一個Promise
,那麼這個新Promise
會決定原Promise
的狀態const promise = new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ice')
}, 3000);
}))
})
promise.then(res => console.log(res))
//3s後 ice
登入後複製
resolve
中傳入的是一個物件,並且這個物件有實現then
方法,那麼會執行該then
方法,then
方法會傳入resolve
,reject
函數。此時的promise
狀態取決於你呼叫了resolve
,還是reject
函數。這種模式也稱之為: thenableconst promise = new Promise((resolve, reject) => {
resolve({
then(res, rej) {
res('hi ice')
}
})
})
promise.then(res => console.log(res))
// hi ice
登入後複製
Promise.prototype
上的方法,也就是Promise的顯示原型上,當我new Promise的時候,會把返回的改物件的 promise[[prototype]](隱式原型) === Promise.prototype (顯示原型)then
方法可以接受引數,一個引數為成功的回撥,另一個引數為失敗的回撥,前面重構requestData
中有演練過。const promise = new Promise((resolve, reject) => {
resolve('request success')
// reject('request error')
})
promise.then(res => console.log(res), rej => console.log(rej))
//request success
登入後複製
null
或""
佔位const promise = new Promise((resolve, reject) => {
// resolve('request success')
reject('request error')
})
promise.then(null, rej => console.log(rej))
//request error
登入後複製
const promise = new Promise((resolve, reject) => {
resolve('hi ice')
})
promise.then(res => ({name:'ice', age:22}))
.then(res => console.log(res))
//{name:'ice', age:22}
登入後複製
then
方法是有返回值的,它的返回值是promise
,但是是promise
那它的狀態如何決定呢?接下來讓我們一探究竟。const promise = new Promise((resolve, reject) => {
resolve('hi ice')
})
promise.then(res => ({name:'ice', age:22}))
.then(res => console.log(res))
//{name:'ice', age:22}
登入後複製
Promise.resolve
,並且把返回值作為實參傳遞到then
方法中。undefined
const promise = new Promise((resolve, reject) => {
resolve('hi ice')
})
promise.then(res => {
return new Promise((resolve, reject) => {
resolve('then 的返回值')
})
}).then(res => console.log(res))
//then 的返回值
登入後複製
promise
物件,狀態和你呼叫resolve
,還是reject
有關const promise = new Promise((resolve, reject) => {
resolve('hi ice')
})
promise.then(res => {
return {
then(resolve, reject) {
resolve('hi webice')
}
}
}).then(res => console.log(res))
//hi webice
登入後複製
resolve
,還是reject
const promise = new Promise((resolve, reject) => {
reject('ice error')
})
promise.catch(err => console.log(err))
promise.catch(err => console.log(err))
promise.catch(err => console.log(err))
//ice error
//ice error
//ice error
登入後複製
resolve
還是reject
const promise = new Promise((resolve, reject) => {
reject('ice error')
})
promise.catch(err => ({name:'ice', age: 22})).then(res => console.log(res))
//{name:'ice', age: 22}
登入後複製
const promise = new Promise((resolve, reject) => {
reject('ice error')
})
promise.catch(err => {
return new Promise((resolve, reject) => {
reject('ice error promise')
})
}).catch(res => console.log(res))
//ice error promise
登入後複製
new Promise()
呼叫了reject
函數,則會被catch
捕獲到const promise = new Promise((resolve, reject) => {
reject('ice error')
})
promise.catch(err => {
return {
then(resolve, reject) {
reject('ice error then')
}
}
}).catch(res => console.log(res))
//ice error then
登入後複製
finally
方法const promise = new Promise((resolve, reject) => {
resolve('hi ice')
})
promise.then(res => console.log(res)).finally(() => console.log('finally execute'))
//finally execute
登入後複製
Promise.resolve('ice')
//等價於
new Promise((resolve, reject) => resolve('ice'))
登入後複製
Promise.reject('ice error')
//等價於
new Promise((resolve, reject) => reject('ice error'))
登入後複製
fulfilled 狀態
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hi ice')
}, 1000);
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hi panda')
}, 2000);
})
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hi grizzly')
}, 3000);
})
Promise.all([promise1, promise2, promise3]).then(res => console.log(res))
//[ 'hi ice', 'hi panda', 'hi grizzly' ]
登入後複製
resolve
狀態的時候才會呼叫.then
方法。.catch
方法rejected狀態
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hi ice')
}, 1000);
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('hi panda')
}, 2000);
})
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hi grizzly')
}, 3000);
})
Promise.all([promise1, promise2, promise3]).then(res => console.log(res)).catch(err => console.log(err))
//hi panda
登入後複製
Promise.all
有一個缺陷,就是當遇到一個rejected的狀態,那麼對於後面是resolve
或者reject
的結果我們是拿不到的Promise.allSettled
,無論狀態是fulfilled/rejected都會把引數返回給我們所有promise都有結果
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('hi ice')
}, 1000);
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hi panda')
}, 2000);
})
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('hi grizzly')
}, 3000);
})
Promise.allSettled([promise1, promise2, promise3]).then(res => console.log(res))
/* [
{ status: 'rejected', reason: 'hi ice' },
{ status: 'fulfilled', value: 'hi panda' },
{ status: 'rejected', reason: 'hi grizzly' }
] */
登入後複製
其中一個promise沒有結果
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('hi ice')
}, 1000);
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hi panda')
}, 2000);
})
const promise3 = new Promise((resolve, reject) => {})
Promise.allSettled([promise1, promise2, promise3]).then(res => console.log(res))
// 什麼都不列印
登入後複製
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('hi error')
}, 1000);
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hi panda')
}, 2000);
})
Promise.race([promise1, promise2])
.then(res => console.log(res))
.catch(e => console.log(e))
//hi error
登入後複製
AggregateError
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('hi error')
}, 1000);
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hi panda')
}, 2000);
})
Promise.any([promise1, promise2])
.then(res => console.log(res))
.catch(e => console.log(e))
//hi panda
登入後複製
function requestData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url.includes('iceweb')) {
resolve(url)
} else {
reject('請求錯誤')
}
}, 1000);
})
}
requestData('iceweb.io').then(res => {
requestData(`iceweb.org ${res}`).then(res => {
requestData(`iceweb.com ${res}`).then(res => {
console.log(res)
})
})
})
//iceweb.com iceweb.org iceweb.io
登入後複製
function requestData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url.includes('iceweb')) {
resolve(url)
} else {
reject('請求錯誤')
}
}, 1000);
})
}
requestData('iceweb.io').then(res => {
return requestData(`iceweb.org ${res}`)
}).then(res => {
return requestData(`iceweb.com ${res}`)
}).then(res => {
console.log(res)
})
//iceweb.com iceweb.org iceweb.io
登入後複製
function requestData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url.includes('iceweb')) {
resolve(url)
} else {
reject('請求錯誤')
}
}, 1000);
})
}
function* getData(url) {
const res1 = yield requestData(url)
const res2 = yield requestData(res1)
const res3 = yield requestData(res2)
console.log(res3)
}
const generator = getData('iceweb.io')
generator.next().value.then(res1 => {
generator.next(`iceweb.org ${res1}`).value.then(res2 => {
generator.next(`iceweb.com ${res2}`).value.then(res3 => {
generator.next(res3)
})
})
})
//iceweb.com iceweb.org iceweb.io
登入後複製
getData
已經變為同步的形式,可以拿到我最終的結果了。那麼很多同學會問,generator一直呼叫.next
不是也產生了回撥地獄嗎?function requestData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url.includes('iceweb')) {
resolve(url)
} else {
reject('請求錯誤')
}
}, 1000);
})
}
function* getData() {
const res1 = yield requestData('iceweb.io')
const res2 = yield requestData(`iceweb.org ${res1}`)
const res3 = yield requestData(`iceweb.com ${res2}`)
console.log(res3)
}
//自動化執行 async await相當於自動幫我們執行.next
function asyncAutomation(genFn) {
const generator = genFn()
const _automation = (result) => {
let nextData = generator.next(result)
if(nextData.done) return
nextData.value.then(res => {
_automation(res)
})
}
_automation()
}
asyncAutomation(getData)
//iceweb.com iceweb.org iceweb.io
登入後複製
async await
的一個變種而已.next
方法function requestData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url.includes('iceweb')) {
resolve(url)
} else {
reject('請求錯誤')
}
}, 1000);
})
}
async function getData() {
const res1 = await requestData('iceweb.io')
const res2 = await requestData(`iceweb.org ${res1}`)
const res3 = await requestData(`iceweb.com ${res2}`)
console.log(res3)
}
getData()
//iceweb.com iceweb.org iceweb.io
登入後複製
getData
生成器函數函數,改為async
函數,yeild
的關鍵字替換為await
就可以實現非同步程式碼同步寫法了。async function sayHi() {
console.log('hi ice')
}
sayHi()
//hi ice
登入後複製
非同步函數的返回值和普通返回值有所區別
undefined
Promise.resolve
(返回值)resolve
,或者reject
有關非同步函數中可以使用await
關鍵字,現在在全域性也可以進行await
,但是不推薦。會阻塞主程序的程式碼執行
async function sayHi() {
console.log(res)
}
sayHi().catch(e => console.log(e))
//或者
async function sayHi() {
try {
console.log(res)
}catch(e) {
console.log(e)
}
}
sayHi()
//ReferenceError: res is not defined
登入後複製
await
關鍵字,普通函數不行resolve或者reject
await
後續的程式碼,所以await
後面的程式碼,相當於包括在.then
方法的回撥中,如果狀態變為rejected,你則需要在函數內部try catch
,或者進行鏈式呼叫進行.catch
操作function requestData(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url.includes('iceweb')) {
resolve(url)
} else {
reject('請求錯誤')
}
}, 1000);
})
}
async function getData() {
const res = await requestData('iceweb.io')
console.log(res)
}
getData()
// iceweb.io
登入後複製
【相關推薦:、】
php入門到就業線上直播課: