1.回調函數(callback)
setTimeout(() => {
// callback 函數體
}, 1000)
缺點:回調地獄,不能用try catch 捕獲錯誤,不能return
try {
setTimeout(() => {
console.log(aa)
}, 1000)
} catch (error) {
}
//報錯:Uncaught ReferenceError: aa is not defined
回調地獄的根本問題在於:
- 缺乏順序性: 回調地獄導致的調試困難,和大腦的思維方式不符
- 嵌套函數存在耦合性,一旦有所改動,就會牽一髮而動全身,即(控制反轉)
- 嵌套函數過多的多話,很難處理錯誤
function a(functionb(){
c(function d(){
})
})
如何解決回調地獄?(看下面的方法)
2.Promise(ES6)
- Promise有三種狀態:pending/reslove/reject 。pending就是未決,resolve可以理解爲成功,reject可以理解爲拒絕。
- 同時Promise常用的三種方法 then 表示異步成功執行後的數據狀態變爲reslove catch 表示異步失敗後執行的數據狀態變爲reject all表示把多個沒有關係的Promise封裝成一個Promise對象使用then返回一個數組數據。
function f(){
let promise = new Promise((resolve, reject) => {
//模擬異步
setTimeout(()=>{
resolve('prom')
},1000)
})
return promise
}
function f1() {
//返回一個Promise用於下一次調用then
return f().then(data=>{
// 返回的數據用於下一次then使用
return data+'ise'
})
}
f1().then(data=>{
console.log(data)
})
console.log("hello word")
結果: hello word
promise
寫成鏈式結構如下
new Promise((resolve, reject) => {
//模擬異步
setTimeout(()=>{
resolve('prom')
},1000)
}).then(data=>{
return data+'ise'
}).then(data=>{
console.log(data)
})
缺點:無法取消 Promise ,錯誤需要通過回調函數來捕獲
3.Generator(生成器,es6)
- Generator(生成器)是一種有效利用內存的機制,一邊循環一邊計算生成數值的機制。通過配合Promise可以更加優雅的寫異步代碼
特點 : 可以控制函數的執行
function *fetch() {
yield ajax('XXX1', () => {})
yield ajax('XXX2', () => {})
yield ajax('XXX3', () => {})
}
let it = fetch()
let result1 = it.next()
let result2 = it.next()
let result3 = it.next()
缺點:生成器不是最完美的,它的語法讓人難以理解
4.Async/await (異步等待, es7)
async、await 是異步的終極解決方案
優點:代碼清晰,不用像 Promise 寫一大堆 then 鏈,處理了回調地獄的問題
缺點:await 將異步代碼改造成同步代碼,如果多個異步操作沒有依賴性而使用 await 會導致性能上的降低。
函數前面加async 表示該函數是一個異步函數 await 表示等待一個異步值的到來
eg1
async function test() {
// 以下代碼沒有依賴性的話,完全可以使用 Promise.all 的方式
// 如果有依賴性的話,其實就是解決回調地獄的例子了
await fetch('XXX1')
await fetch('XXX2')
await fetch('XXX3')
}
異步函數可以更加方便的同Promise結合使用來書寫同步代碼風格的異步執行
eg2:
function f() {
return new Promise((resolve, reject) => {
setTimeout(()=>{
resolve("hello word")
},1000)
})
}
async function a(){
var data = await f();
return data;
}
a().then(data=>{
console.log(data)
})