美文网首页
JavaScript同步、异步、回调执行顺序之经典setTime

JavaScript同步、异步、回调执行顺序之经典setTime

作者: 一像素 | 来源:发表于2017-10-16 10:29 被阅读0次

破解口诀:同步优先、异步靠边、回调垫底

for (var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log('i--- ',i);
    }, 1000);
}
console.log(i);
//输出
5
i---  5
i---  5
i---  5
i---  5
i---  5

为什么是输出是这样呢?下面我给大家分析一下
1、for循环和循环外的console是同步的,所以先执行for循环,再执行外部的console.log。(同步优先)
2、for循环里面有一个setTimeout回调,他是垫底的存在,只能最后执行。(回调垫底)
分析:
for循环先执行,但是不会给setTimeout传参(回调垫底),等for循环执行完,就会给setTimeout传参,而外部的console打印出5是因为for循环执行完成了。
内部的setTimeout回调执行的时候 因为for循环已经执行完了 所以这个时候i=5 给setTimeout传参(5) 所以setTimeout内部的console.log输出的就是 5;

下面我们加一行代码仔细看一下这个输出的过程:

for (var i = 0; i < 5; ++i) {
    setTimeout(function() {
        console.log('s---',i);
    }, 1000);
    console.log('c---', i); //新加一行代码
}
console.log(i);
 
//输出
c---  0
c---  1
c---  2
c---  3
c--- 4
5 //console.log(i);输出的
s---  5
s--- 5
s---  5
s---  5
s---  5

这个时候面试官也许会问你,怎么才能正常输出0,1,2,3,4呢?
下面给出两个方法:

方法一:
for (let i = 0; i < 5; ++i) {
    setTimeout(function() {
        console.log('s--- ',i);
    }, 1000);
}
 
console.log(i);
 
//输出
i is not defined
s---   0
s---   1
s---   2
s---   3
s---   4

分析:
我们来分析一下,用了let作为变量i的定义之后,
for循环每执行一次,都会先给setTimeout传参,
准确的说是给loop传参,loop形成了一个闭包,
这样就执行了5个loop,每个loop传的参数分别是0,1,2,3,4
然后loop里面的setTimeout会进入消息队列排队等候。
当外部的console执行完毕,因为for循环里的i变成了
一个新的变量 _i ,所以在外部的console.log(i)是不存在的。

方法二:
var loop = function (_i) {
    setTimeout(function() {
        console.log('2:', _i);
    }, 1000);
};
 
for (var _i = 0; _i < 5; _i++) {
    loop(_i);
}
 
console.log(i);

上面主要讲了同步和回调执行顺序的问题,接着我就举一个包含同步、异步、回调的例子。

let a = new Promise(
  function(resolve, reject) {
    console.log(1)
    setTimeout(() => console.log(2), 0)
    console.log(3)
    console.log(4)
    resolve(true)
  }
)
a.then(v => {
  console.log(8)
})
 
let b = new Promise(
  function() {
    console.log(5)
    setTimeout(() => console.log(6), 0)
  }
)
console.log(7)

口诀最重要 回忆一下(同步-异步-回调)
下面我们来分析一下:

1.看同步代码:a变量是一个Promise,我们知道Promise是异步的,
是指他的then()和catch()方法,Promise本身还是同步的,
所以这里先执行a变量内部的Promise同步代码。(同步优先)
2、Promise内部有4个console,第二个是一个setTimeout回调
(回调垫底)。所以这里先输出1,3,4回调的方法丢到消息队列中
排队等着。
3、接着执行resolve(true),进入then(),then是异步,
下面还有同步没执行完呢,所以then也去消息队列排队等候
(异步靠边)
4、b变量也是一个Promise,和a一样,执行内部的同步代码,
输出5,setTimeout滚去消息队列排队等候。
5、最下面同步输出7。
6、同步的代码执行完了,JavaScript就跑去消息队列呼叫异步的
代码:异步,出来执行了。这里只有一个异步then,所以输出8。
7、异步也over,轮到回调的孩子们:回调,出来执行了。这里有
2个回调在排队,他们的时间都设置为0,所以不受时间影响,
只跟排队先后顺序有关。则先输出a里面的回调2,最后输出b里面
的回调6。(这里 如果时间不一样的话 执行顺序就要根据时间先
后来输出)
8、最终输出结果就是:1、3、4、5、7、8、2、6。

相关文章

  • JavaScript同步、异步、回调执行顺序之经典setTime

    破解口诀:同步优先、异步靠边、回调垫底 为什么是输出是这样呢?下面我给大家分析一下1、for循环和循环外的cons...

  • 04-Node 异步编程

    Node 异步编程同步方法和异步方法异步 API 的执行顺序异步编程回调地狱问题Promise 改造回调地狱代码a...

  • nodejs--day4笔记

    1. 同步与异步API 回调函数 通过回调函数返回异步API的值 代码执行顺序 2. promise 解决回调...

  • 同步、异步、回调执行顺序

    看下面例子判断输出的值 在看正确结果之前,我先进行分析题目(同步 => 异步 => 回调): 1).看同步代码:a...

  • 同步、异步、回调执行顺序

  • JS同步回调和异步回调

    同步回调函数 按照正常顺序执行 输出为: 异步回调函数 setTimeout将回调函数放在下一个任务队列执行 输出为

  • 非阻塞和阻塞

    ### 同步 任务的执行顺序和程序的执行顺序一致,所以是同步的。 ### 异步 每一个任务都有一个或多个回调函数,...

  • 回调函数callback

    异步 和 同步 同步:按照顺序,完成一个再进行下一个。 异步:不等这个执行完就能执行下一个。 回调函数 callb...

  • GCD篇(2)

    这里的运行顺序都是指执行顺序,如果是异步回调方式的执行顺序要分情况。 1.group之并发异步 运行结果 disp...

  • JS 同步和异步

    JavaScript是典型的单线程。 同步任务都放在主线程上执行,形成一个执行栈。 异步任务:JS的异步是通过回调...

网友评论

      本文标题:JavaScript同步、异步、回调执行顺序之经典setTime

      本文链接:https://www.haomeiwen.com/subject/wzfkuxtx.html