兩天更新完。
const promise = new Promise((resolve, reject) => {console.log(1);console.log(2);
});
promise.then(() => {console.log(3);
});
console.log(4);
//1
//2
//4
promise.then 是微任務,它會在所有的宏任務執行完之后才會執行,同時需要promise內部的狀態發生變化,因為這里內部沒有發生變化,一直處于pending狀態,所以不輸出3。
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);
/*
promise1
1 Promise{<resolved>: resolve1}
2 Promise{<pending>}
resolve1
*/
直接打印Promise,會打印出它的狀態值和參數。
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);
/*
1
2
4
timerStart
timerEnd
success
*/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');
/*
start
promise1
timer1
promise2
timer2
*/
代碼執行過程如下:
- 首先,Promise.resolve().then是一個微任務,加入微任務隊列
- 執行timer1,它是一個宏任務,加入宏任務隊列
- 繼續執行下面的同步代碼,打印出start
- 這樣第一輪宏任務就執行完了,開始執行微任務Promise.resolve().then,打印出promise1
- 遇到timer2,它是一個宏任務,將其加入宏任務隊列,此時宏任務隊列有兩個任務,分別是timer1、timer2;
- 這樣第一輪微任務就執行完了,開始執行第二輪宏任務,首先執行定時器timer1,打印timer1;
- 遇到Promise.resolve().then,它是一個微任務,加入微任務隊列
- 開始執行微任務隊列中的任務,打印promise2;
- 最后執行宏任務timer2定時器,打印出timer2;
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);
})
/*
then:success1
考察的就是Promise的狀態在發生變化之后,就不會再發生變化
*/Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)
/*
1
*/
then方法接受的參數是函數,而如果傳遞的并非是一個函數,這就會導致前一個Promise的結果會傳遞下面。Promise.resolve(3) 是一個 Promise 對象,不是一個函數。所以這個參數也被忽略。
const promise1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('success')//狀態改變}, 1000)
})
const promise2 = promise1.then(() => {//注意這是promise2throw new Error('error!!!')
})
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {console.log('promise1', promise1)console.log('promise2', promise2)
}, 2000)
/*
promise1 Promise {<pending>}
promise2 Promise {<pending>}
promise1 Promise {<fulfilled>: "success"}
promise2 Promise {<rejected>: Error: error!!}
*/Promise.resolve(1).then(res => {console.log(res);//輸出1return 2;//給到了最后的.then}).catch(err => {return 3;}).then(res => {console.log(res);//輸出2});
/*
1
2
*/
Promise是可以鏈式調用的,由于每次調用 .then 或者 .catch 都會返回一個新的 promise,從而實現了鏈式調用, 它并不像一般任務的鏈式調用一樣return this。
上面的輸出結果之所以依次打印出1和2,是因為resolve(1)之后走的是第一個then方法,并沒有進catch里,所以第二個then中的res得到的實際上是第一個then的返回值。并且return 2會被包裝成resolve(2),被最后的then打印輸出2。
Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)//1
只需要記住一個原則:.then 或.catch 的參數期望是函數,傳入非函數則會發生值透傳。就是當它不存在。
第一個then和第二個then中傳入的都不是函數,一個是數字,一個是對象,因此發生了透傳,將resolve(1) 的值直接傳到最后一個then里,直接打印出1。
Promise.resolve().then(() => {return new Error('error!!!')
}).then(res => {console.log("then: ", res)
}).catch(err => {console.log("catch: ", err)
})
/*
"then: " "Error: error!!!"
*/
返回任意一個非 promise 的值都會被包裹成 promise 對象,因此這里的return new Error(‘error!!!’)也被包裹成了return Promise.resolve(new Error(‘error!!!’)),因此它會被then捕獲而不是catch。
const promise = Promise.resolve().then(() => {return promise;
})
promise.catch(console.err)
/*
Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
*/
這里其實是一個坑,.then 或 .catch 返回的值不能是 promise 本身,否則會造成死循環。
Promise.reject('err!!!').then((res) => {console.log('success', res)}, (err) => {console.log('error', err)}).catch(err => {console.log('catch', err)})//error err!!!
錯誤直接被then的第二個參數捕獲了,所以就不會被catch捕獲了
Promise.resolve('1').then(res => {console.log(res)}).finally(() => {console.log('finally')})
Promise.resolve('2').finally(() => {console.log('finally2')return '我是finally2返回的值'}).then(res => {console.log('finally2后面的then函數', res)})
/* 注意一下微任務隊列順序,Promise.resolve是同步代碼 因為創建了一個promise
1
finally2
finally
finally2后面的then函數 2
*/function runAsync (x) {const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))return p
}Promise.all([runAsync(1), runAsync(2), runAsync(3)]).then(res => console.log(res))
/*
1
2
3
[1, 2, 3]
*/function runAsync (x) {const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))return p
}
function runReject (x) {const p = new Promise((res, rej) => setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x))
/*
`Error: ${x}`并不會打印,作為rejected 的原因傳入
*/return p
}
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)]).then(res => console.log(res)).catch(err => console.log(err))
/*
// 1s后輸出
1
3
// 2s后輸出
2
Error: 2 //進入catch
// 4s后輸出
4
*/function runAsync(x) {const p = new Promise(r =>setTimeout(() => r(x, console.log(x)), 1000));return p;
}
function runReject(x) {const p = new Promise((res, rej) =>setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x));return p;
}
Promise.race([runReject(0), runAsync(1), runAsync(2), runAsync(3)]).then(res => console.log("result: ", res)).catch(err => console.log(err));
/* 雖然race只捕獲一次,但settimeout回調函數輸出還是有的
0
Error: 0
1
2
3
*/async function async1() {console.log("async1 start");await async2();console.log("async1 end");
}
async function async2() {console.log("async2");
}
async1();
console.log('start')
/*
async1 start
async2
start
async1 end跳出async1函數后,執行同步代碼start;在一輪宏任務全部執行完之后,再來執行await后面的內容async1 end。
await后面的語句相當于放到了new Promise中,下一行及之后的語句相當于放在Promise.then中。
*/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")
/*
async1 start
async2
start
async1 end
timer2
timer3
timer1
*/
代碼的執行過程如下:
- 首先進入async1,打印出async1 start;
- 之后遇到async2,進入async2,遇到定時器timer2,加入宏任務隊列,之后打印async2;
- 由于async2阻塞了后面代碼的執行,所以執行后面的定時器timer3,將其加入宏任務隊列,之后打印start;
- 然后執行async2后面的代碼,打印出async1 end,遇到定時器timer1,將其加入宏任務隊列;
- 最后,宏任務隊列有三個任務,先后順序為timer2,timer3,timer1,沒有微任務,所以直接所有的宏任務按照先進先出的原則執行。
async function async1 () {console.log('async1 start');await new Promise(resolve => {console.log('promise1')})console.log('async1 success');return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')
/*
script start
async1 start
promise1
script end
async1中await后面的Promise是沒有返回值的,也就是它的狀態始終是pending狀態,所以在await之后的內容是不會執行的,包括async1后面的 .then。
*/