一.基礎篇
1.1
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
})
console.log('1', promise1);
分析:
- 從上至下,先遇到new Promise,執行該構造函數中的代碼promise1(此代碼是同步的)
- 然後執行同步代碼1,此時promise1沒有被resolve或者reject,是以狀态還是pending
結果:
‘promise1’
‘1’ Promise{}
1.2
const promise = new Promise((resolve, reject) => {
console.log(1);
resolve('success')
console.log(2);
});
promise.then(() => {
console.log(3);
});
console.log(4);
分析:
- 從上至下,先遇到new Promise,執行其中的同步代碼1
- 再遇到resolve(‘success’), 将promise的狀态改為了resolved并且将值儲存下來
- 繼續執行同步代碼2
- 跳出promise,往下執行,碰到promise.then這個微任務,将其加入微任務隊列
- 執行同步代碼4
- 本輪宏任務全部執行完畢,檢查微任務隊列,發現promise.then這個微任務且狀态為resolved,執行它。
結果:
1 2 4 3
1.3
const promise = new Promise((resolve, reject) => {
console.log(1);
console.log(2);
});
promise.then(() => {
console.log(3);
});
console.log(4);
分析:
和題目二相似,隻不過在promise中并沒有resolve或者reject
是以promise.then并不會執行,它隻有在被改變了狀态之後才會執行。
結果:
1 2 4
1.4
const promise1 = new Promise((resolve, reject) => {
console.log('promise1')
resolve('resolve1')
})
const promise2 = promise1.then(res => {
console.log(res)
})
console.log('1', promise1);
console.log('2', promise2);
分析:
從上至下,先遇到new Promise,執行該構造函數中的代碼promise1
碰到resolve函數, 将promise1的狀态改變為resolved, 并将結果儲存下來
碰到promise1.then這個微任務,将它放入微任務隊列
promise2是一個新的狀态為pending的Promise
執行同步代碼1, 同時列印出promise1的狀态是resolved
執行同步代碼2,同時列印出promise2的狀态是pending
宏任務執行完畢,查找微任務隊列,發現promise1.then這個微任務且狀态為resolved,執行它。
結果:
‘promise1’
‘1’ Promise{: ‘resolve1’}
‘2’ Promise{}
‘resolve1’
二.結合setTimeout
1.1
console.log('start')
setTimeout(() => {
console.log('time')
})
Promise.resolve().then(() => {
console.log('resolve')
})
console.log('end')
分析:
剛開始整個腳本作為一個宏任務來執行,對于同步代碼直接壓入執行棧進行執行,是以先列印出start和end。
setTimout作為一個宏任務被放入宏任務隊列(下一個)
Promise.then作為一個微任務被放入微任務隊列
本次宏任務執行完,檢查微任務,發現Promise.then,執行它
接下來進入下一個宏任務,發現setTimeout,執行。
結果:
‘start’
‘end’
‘resolve’
‘time’
1.2
const promise = new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log("timerStart");
resolve("success");
console.log("timerEnd");
}, 0);
console.log(2);
});
promise.then((res) => {
console.log(res);
});
console.log(4);
分析:
從上至下,先遇到new Promise,執行該構造函數中的代碼1
然後碰到了定時器,将這個定時器中的函數放到下一個宏任務的延遲隊列中等待執行
執行同步代碼2
跳出promise函數,遇到promise.then,但其狀态還是為pending,這裡了解為先不執行
執行同步代碼4
一輪循環過後,進入第二次宏任務,發現延遲隊列中有setTimeout定時器,執行它
首先執行timerStart,然後遇到了resolve,将promise的狀态改為resolved且儲存結果并将之前的promise.then推入微任務隊列
繼續執行同步代碼timerEnd
宏任務全部執行完畢,查找微任務隊列,發現promise.then這個微任務,執行它。
結果:
結果就不給啦,自己去試試吧
1.3
Promise.resolve().then(() => {
console.log('promise1');
const timer2 = setTimeout(() => {
console.log('timer2')
}, 0)
});
const timer1 = setTimeout(() => {
console.log('timer1')
Promise.resolve().then(() => {
console.log('promise2')
})
}, 0)
console.log('start');
分析:
剛開始整個腳本作為第一次宏任務來執行,我們将它标記為宏1,從上至下執行
遇到Promise.resolve().then這個微任務,将then中的内容加入第一次的微任務隊列标記為微1
遇到定時器timer1,将它加入下一次宏任務的延遲清單,标記為宏2,等待執行(先不管裡面是什麼内容)
執行宏1中的同步代碼start
第一次宏任務(宏1)執行完畢,檢查第一次的微任務隊列(微1),發現有一個promise.then這個微任務需要執行
執行列印出微1中同步代碼promise1,然後發現定時器timer2,将它加入宏2的後面,标記為宏3
第一次微任務隊列(微1)執行完畢,執行第二次宏任務(宏2),首先執行同步代碼timer1
然後遇到了promise2這個微任務,将它加入此次循環的微任務隊列,标記為微2
宏2中沒有同步代碼可執行了,查找本次循環的微任務隊列(微2),發現了promise2,執行它
第二輪執行完畢,執行宏3,列印出timer2
結果:
‘start’
‘promise1’
‘timer1’
‘promise2’
‘timer2’
promise中的then,catch
1.1
const promise = new Promise((resolve, reject) => {
resolve("success1");
reject("error");
resolve("success2");
});
promise
.then(res => {
console.log("then: ", res);
}).catch(err => {
console.log("catch: ", err);
})
分析:
構造函數中的 resolve 或 reject 隻有第一次執行有效,多次調用沒有任何作用 。
結論:Promise的狀态一經改變就不能再改變。
是以答案是什麼呢?
1.2
const promise = new Promise((resolve, reject) => {
reject("error");
resolve("success2");
});
promise
.then(res => {
console.log("then1: ", res);
}).then(res => {
console.log("then2: ", res);
}).catch(err => {
console.log("catch: ", err);
}).then(res => {
console.log("then3: ", res);
})
結果:
"catch: " “error”
"then3: " undefined
分析:
至于then3也會被執行,那是因為catch()也會傳回一個Promise,且由于這個Promise沒有傳回值,是以列印出來的是undefined。
1.3
Promise.resolve(1)
.then(res => {
console.log(res);
return 2;
})
.catch(err => {
return 3;
})
.then(res => {
console.log(res);
});
結果: 1 2
分析:
Promise可以鍊式調用,不過promise 每次調用 .then 或者 .catch 都會傳回一個新的 promise,進而實作了鍊式調用, 它并不像一般我們任務的鍊式調用一樣return this。
上面的輸出結果之是以依次列印出1和2,那是因為resolve(1)之後走的是第一個then方法,并沒有走catch裡,是以第二個then中的res得到的實際上是第一個then的傳回值。
且return 2會被包裝成resolve(2)。
async and await
1.1
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
async1();
console.log('start')
注:這裡首先要明白async和promise的關系,明白用promise形式是如何書寫代碼的哦,可以檢視async和await的簡介
上面代碼等同于
// 等同于
function async1(){
return new Promise((resolve,reject)=> {
console.log("async1 start");
async2().tnen(res => {
console.log("async1 end");
resolve()
})
})
}
function async2(){
return new Promise((resolve,reject) => {
console.log("async2");
})
}
async1()
console.log('start')
這下知道結果是什麼了吧
1.2
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
setTimeout(() => {
console.log('timer')
}, 0)
console.log("async2");
}
async1();
console.log("start")
結果:
‘async1 start’
‘async2’
‘start’
‘async1 end’
‘timer’
1.3
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
setTimeout(() => {
console.log('timer1')
}, 0)
}
async function async2() {
setTimeout(() => {
console.log('timer2')
}, 0)
console.log("async2");
}
async1();
setTimeout(() => {
console.log('timer3')
}, 0)
console.log("start")
哈哈哈,有沒有繞暈你呀,自己去解鎖吧