setTimeout、setInterval、promise、async/await的顺序详解(多种情况,非常详细~)
本文很長,列舉的情況很多。
在閱讀本文之前,如果您有充足的時間,請新建一個項目與本文一同實踐。
每段代碼都有對應的解釋,但是自己動手嘗試印象才會更深哦~
setInterval:表示多久執行一次,需要clearInterval(timer)來讓它停下。要是不clearInterval(timer),它就會越來越快!
setTimeout:表示過了多久之后執行,只會執行一次!
比如這段代碼,實現的是每秒都在console里輸出現在的時間,5秒后停止。
上代碼
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Test</title></head><body><div id="root"></div><script>let timertimer = setInterval(function () {console.log(new Date())}, 1000)setTimeout(function () {clearInterval(timer)}, 5000)</script></body>
</html>
運行結果:
如果setTimeout設置時間為0呢?
修改一下代碼:
<script>let timertimer = setInterval(function () {console.log(new Date())}, 1000)setTimeout(function () {clearInterval(timer)}, 5000)setTimeout(function () {console.log('hello')}, 0)</script>
運行結果:
加上promise
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Test</title></head><body><div id="root"></div><script>console.log('1')setTimeout(() => {console.log('2')}, 0)let promise = new Promise((resolve, reject) => {setTimeout(() => {console.log('3')}, 0)console.log('4')})promise.then((res) => {console.log('5')}).then((res) => {console.log('6')})console.log('7')</script></body>
</html>
看下結果:
這一段完全沒有調用到。
promise.then((res) => {console.log('5')}).then((res) => {console.log('6')})
為啥呢,因為沒有resolve()
加上resolve()之后呢?
<script>console.log('1')setTimeout(() => {console.log('2')}, 0)let promise = new Promise((resolve, reject) => {setTimeout(() => {console.log('3')setTimeout(() => {resolve()}, 0)}, 0)console.log('4')})promise.then((res) => {console.log('5')}).then((res) => {console.log('6')})console.log('7')</script>
那是不是什么時候resolve()就什么時候輸出呢?
答案是:不是
把“2”換到下面來試一下:
<script>console.log('1')let promise = new Promise((resolve, reject) => {setTimeout(() => {console.log('3')setTimeout(() => {resolve()}, 0)}, 0)console.log('4')})setTimeout(() => {console.log('2')}, 0)promise.then((res) => {console.log('5')}).then((res) => {console.log('6')})console.log('7')</script>
可見3和2的位置確實變了,但是promise部分,就是5和6,仍然是最后出現。
那有多個setTimeout會怎樣呢?我們加一個“2.5”試一下:
<script>console.log('1')setTimeout(() => {console.log('2.5')}, 0)let promise = new Promise((resolve, reject) => {setTimeout(() => {console.log('3')setTimeout(() => {resolve()}, 0)}, 0)console.log('4')})setTimeout(() => {console.log('2')}, 0)promise.then((res) => {console.log('5')}).then((res) => {console.log('6')})console.log('7')</script>
輸出結果是:
可見是從上至下的啊~
如果讓resolve()和console.log(‘3’)擺在一起呢?
<script>console.log('1')setTimeout(() => {console.log('2.5')}, 0)let promise = new Promise((resolve, reject) => {setTimeout(() => {console.log('3')resolve()}, 0)console.log('4')})setTimeout(() => {console.log('2')}, 0)promise.then((res) => {console.log('5')}).then((res) => {console.log('6')})console.log('7')</script>
執行結果:
可見,在setTimeout里套的setTimeout會被最后執行。
如果改一下執行時間呢?把2.5輸出的時間改為運行0.1s之后?
<script>console.log('1')setTimeout(() => {console.log('2.5')}, 100)let promise = new Promise((resolve, reject) => {setTimeout(() => {console.log('3')setTimeout(() => {resolve()}, 0)}, 0)console.log('4')})setTimeout(() => {console.log('2')}, 0)promise.then((res) => {console.log('5')}).then((res) => {console.log('6')})console.log('7')</script>
執行結果:
它會出現在最后!
那如果resolve()執行時間延后呢?
<script>console.log('1')let promise = new Promise((resolve, reject) => {setTimeout(() => {console.log('3')resolve()}, 100)console.log('4')})setTimeout(() => {console.log('2')}, 0)promise.then((res) => {console.log('5')}).then((res) => {console.log('6')})console.log('7')</script>
運行結果:
該先執行的還是先執行了啊~
加上async/await會怎樣?神奇的事發生了!
<script>console.log('1')setTimeout(() => {console.log('2.5')}, 0)let promise = new Promise((resolve, reject) => {setTimeout(() => {console.log('3')resolve()}, 0)console.log('4')})setTimeout(() => {console.log('2')}, 0)async function async1() {console.log('async1 start')await async2()console.log('async1 end')}async function async2() {console.log('async2')}console.log('script start')async1()console.log('script end')promise.then((res) => {console.log('5')}).then((res) => {console.log('6')})console.log('7')</script>
輸出結果是:
async 函數返回一個 Promise 對象,當函數執行的時候,一旦遇到 await 就會先返回,等到觸發的異步操作完成,再執行函數體內后面的語句。可以理解為,是讓出了線程,跳出了 async 函數體。
setTimeout會在async/await之后再執行。但promise的內容會在async/await之前執行。
混亂起來了:把setTimeout塞進async/await中會怎么樣?
<script>console.log('1')setTimeout(() => {console.log('2.5')}, 0)let promise = new Promise((resolve, reject) => {setTimeout(() => {console.log('3')resolve()}, 0)console.log('4')})setTimeout(() => {console.log('2')}, 0)async function async1() {console.log('async1 start')setTimeout(() => {console.log('async1 start setTimeout')}, 0)await async2()console.log('async1 end')setTimeout(() => {console.log('async1 end setTimeout')}, 0)}async function async2() {console.log('async2')setTimeout(() => {console.log('async2 setTimeout')}, 0)setTimeout(() => {console.log('async2 setTimeout after')}, 100)}console.log('script start')async1()console.log('script end')promise.then((res) => {console.log('5')}).then((res) => {console.log('6')})console.log('7')</script>
輸出結果:(看仔細了哦)
所以塞在async/await中的setTimeout會被最后執行。
終極混亂:
let promise = new Promise((resolve, reject) => {setTimeout(() => {console.log('3')setTimeout(() => {resolve()}, 0)}, 0)console.log('4')})
在Promise里的setTimeout里的setTimeout里的resolve()是什么時候執行的?
完整代碼:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Test</title></head><body><div id="root"></div><script>console.log('1')setTimeout(() => {console.log('2.5')}, 0)let promise = new Promise((resolve, reject) => {setTimeout(() => {console.log('3')setTimeout(() => {resolve()}, 0)}, 0)console.log('4')})setTimeout(() => {console.log('2')}, 0)async function async1() {console.log('async1 start')setTimeout(() => {console.log('async1 start setTimeout')}, 0)await async2()console.log('async1 end')setTimeout(() => {console.log('async1 end setTimeout')}, 0)}async function async2() {console.log('async2')setTimeout(() => {console.log('async2 setTimeout')}, 0)setTimeout(() => {console.log('async2 setTimeout after')}, 100)}console.log('script start')async1()console.log('script end')promise.then((res) => {console.log('5')}).then((res) => {console.log('6')})console.log('7')</script></body>
</html>
輸出結果:
啊,原來是這樣,這一部分會被最后執行!
(作者已經要陷入混亂中了…)
休息一下…接著做~
setTimeout的層疊實驗:
<script>setTimeout(() => {console.log('1')setTimeout(() => {console.log('1.2.before3')setTimeout(() => {console.log('1.3.1')}, 0)setTimeout(() => {console.log('1.3.2')}, 0)}, 0)setTimeout(() => {console.log('1.2.after3')}, 0)}, 0)setTimeout(() => {console.log('2')setTimeout(() => {console.log('2.2.1')}, 0)setTimeout(() => {console.log('2.2.2')}, 0)}, 0)setTimeout(() => {console.log('3')}, 0)</script>
輸出結果:
事實證明,setTimeout是一層一層來的,理解好“第幾批”很重要。
可以自己嘗試一下,這個如金字塔一樣的結構,先搭好第一層地基,才會向上搭建這種思想。
至此你已經看完了所有的內容,感謝觀看,實操大于理解,還是建議讀者新建一個項目自己動手嘗試各種情況,還有更多嵌套情況本文沒有列出,如有勤奮的同學列舉,歡迎討論~
補充:
setTimeout并不是準時的原因
- 因為 JavaScript 是一個單線程序的解釋器,因此一定時間內只能執行一段代碼。
- 為了控制要執行的代碼,就有一個 JavaScript 任務隊列。
- 這些任務會按照將它們添加到隊列的順序執行。
- setTimeout() 的第二個參數告訴 JavaScript 再過多長時間把當前任務添加到隊列中。如果隊列是空的,那么添加的代碼會立即執行;如果隊列不是空的,那么它就要等前面的代碼執行完了以后再執行
總結
以上是生活随笔為你收集整理的setTimeout、setInterval、promise、async/await的顺序详解(多种情况,非常详细~)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [JAVA EE] JPA 技术实践:完
- 下一篇: [JS] undefined、null、