本文很长,列举的情况很多。
在阅读本文之前,如果您有充足的时间,请新建一个项目与本文一同实践。
每段代码都有对应的解释,但是自己动手尝试印象才会更深哦~
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是一层一层来的,理解好“第几批”很重要。
可以自己尝试一下,这个如金字塔一样的结构,先搭好第一层地基,才会向上搭建这种思想。
至此你已经看完了所有的内容,感谢观看,实操大于理解,还是建议读者新建一个项目自己动手尝试各种情况,还有更多嵌套情况本文没有列出,如有勤奋的同学列举,欢迎讨论~
补充: