進入個人部落格 Eighteen Blog
異步函數我們經常會用到,最為常見的就是ajax,利用ajax請求我們的服務端擷取資料,然後執行回調函數。
一,普通的ajax
ajax(url,(res)=>{
console.log(res);
})
最普通的異步請求函數,那麼當我們有兩個異步請求,且請求B需要依賴請求A的時候,該怎麼處理?
//ajaxA
ajax(url1, (resA) => {
ajax(url2, (resB) => {
console.log(resA);
console.log(resB);
// ajax(url3, ()=>{} ... 類似這樣有多少個依賴關系就一直嵌套,形成回調地獄(函數多層嵌套)。
})
})
這樣處理我們的多層異步依賴,會最終形成金字塔的形狀,層層嵌套,看不清代碼邏輯,難以維護且難以追蹤。
二,使用promise處理異步回調,使其變成鍊式調用。
new Promise((resolve, reject) => {
ajax(url, (res)=>{
resolve(res)//完成狀态 promise的狀态隻可定義一次,下一行的reject将不起作用。
reject('reject')//拒絕狀态
})
})
.then(res => {
return new Promise((resolve, reject) => {
//如果第二個為異步函數,繼續return 一個promise,resolve的參數即是下個回調的參數。
ajax(url, (res) => {
resolve(res);
})
})
})
.then(res => {
return '非異步';//return 的值是下一個then中的參數。
})
.then(res => {
console.log(res); // "非異步"
})
至此,我們的代碼看起來清晰了不少,當然我們可以遵守盡量給函數語義命名的規則,進一步的簡化代碼。
// 變量聲明函數
let promise1 = new Promise((resolve, reject) => {
ajax(url, (res)=>{
resolve(res)//完成狀态 promise的狀态隻可定義一次,下一行的reject将不起作用。
reject('reject')//拒絕狀态
})
})
let promise2 = new Promise((resolve, reject) => {
//如果第二個依然為異步函數,繼續return 一個new promise,resolve的參數即是下個回調的參數。
ajax(url, (res)=>{
resolve(res)
})
})
promise1()
.then(promise2)
.then(res => {
return '非異步';//return 的值是下一個then中的參數。
})
.then(res => {
console.log(res); // "非異步"
})
這樣代碼更加的簡介清晰。
三,我們可以使用async和await解決回調問題。
function takeLongTime() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(10), 1000);
});
}
function takeLongTime2(v) {
console.log(v); // 10
return new Promise(resolve => {
setTimeout(() => resolve(v + 20), 10);
});
}
async function test() {
const v = await takeLongTime(); //10
const b = await takeLongTime2(v); //30
console.log(b);
}
test();
await 我們從名字可以看出來意思是等待異步的意思,即它可以讓異步回調變得像同步函數,并且會阻塞下一步,但是!這一切都是發生在async中的,而async是異步的,是以整個js并不會被阻塞。是以await要寫在async中。當然單純的await和async是并不能解決問題。可以看到還是需要promise的。
async和await内部實作了Generator ,然後結合promise,是他們的文法糖,大家可以自行了解一下。(它可以使函數内部分步執行)