js的同步与异步

同步优先、异步靠边、回调垫底

世界上的所有事情大致可以分为同步去做和异步去做两种。你打电话去订酒店,电话另一边的工作人员需要查下他们的管理系统才能告诉你有没有房间。

这时候你有两种选择:一种是不挂电话一直等待,直到工作人员查到为止(可能几分钟也可能几个小时,取决于他们的办事效率),这就是同步的。

另一种是工作人员问了你的联系方式就挂断了电话,等他们查到之后再通知你,这就是异步的,这时候你就可以干点其他事情,比如把机票也定了之类的

异步

A发起一个操作后(一般都是比较耗时的操作,如果不耗时的操作就没有必要异步了),可以继续自顾自的处理它自己的事儿,不用干等着这个耗时操作返回。可以达到避免调用线程阻塞的目的。类型多线程,其实,异步是目的,而多线程是实现这个目的的方法

同步

按照顺序向下执行,如果上面的操作卡死,可能导致整个操作卡死

  • 伪异步:正常情况看,确实是异步执行的
<script>
  console.log(1);
  setTimeout(function(){
    console.log(2);
  },500);
  console.log(3);
  // 运行结果
  // 1
  // 3
  // 2
</script>
  • 问题来了,代码如下
<script>
  var date = new Date();
  console.log('first time: ' + date.getTime());
  setTimeout(function(){
      var date1 = new Date();
      console.log('second time: ' + date1.getTime() );
      console.log( date1.getTime() - date.getTime() );
  },1000);
  for(var i=0; i < 10000 ; i++){
      console.log(1);
  }
  // 运行结果
  // first time: 1524540272462
  // (10000)1
  // second time: 1524540274346
  // 1884
</script>
  • 如果setTimeout是异步的,神奇的事情出现了,假设js是异步,那么结果应该是这样的:
// first time: 1524540272462
//(x)1
// second time: 1524540273462
// 1000
//(10000-x)1
x为一秒内打印的1的数量。
  • 异步应该:当执行到setTimeout时,执行下面的for循环,setTimeout执行结束后,打印setTimeout的数据,打印完成后继续执行剩下的for循环。
  • 但是实际结果是执行到setTimeout后,跳出执行for循环,for循环走完后才开始执行setTimeout
  • settimeout并非是1000毫秒后执行的,而是1884毫秒也能看出来是同步的。这里实际是获取到date后,跳过了setTimeout,for训话执行了884毫秒,然后延迟1000毫秒,才执行到date1.getTime() - date.getTime()
另外如果setTimeout时间设置成0秒,也不是说没有延迟,比如:
function a()
{
	setTimeout(function(){console.log(1);},0);
	console.log(2);
}
a();
  • 这里执行的结果任然是2 1,延时0指的是2执行后,没有延时,立刻执行1

思考题1

//4.    What will be written to the console for the following code snippet?

(function () {

        console.log(1);

        setTimeout(function () {
            console.log(2);
        }, 100);

        console.log(3);

        setTimeout(function () {
            console.log(4);
        }, 0);

        console.log(5);

    })()

结果应该为1,3,5,4,2

思考题2

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

结果应该为5,5,5,5,5

  • 分析

1)for循环和循环体外部的console是同步的,所以先执行for循环,再执行外部的console.log。(同步优先)

2)for循环里面有一个setTimeout回调,他是垫底的存在,只能最后执行。(回调垫底)

总结

setTimeout并不是真正的异步操作,只是把想执行的代码放到UI队列中,在未来执行。

原文地址:https://www.cnblogs.com/faramita/p/11306114.html