0%

异步和单线程

我们首先来看一段代码

1
2
3
4
5
console.log(100);
setTimeout(function () {
console.log(200)
}, 1000);
console.log(300);

或许你觉得输出的结果应该是按照100,间隔一秒输出200,然后输出300的方式打印。但事实不然,正确的结果是100,300,间隔一秒输出200。

同步和异步的区别在于有没有阻塞程序进行,上面说的后者就没有阻塞程序的进行,这就是所谓的异步。

程序正常执行过程中,由于JS的单线程特性,一次不可以执行多个任务。在遇到异步代码的时候,会将异步代码放到任务队列里面,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。并且所有同步任务都在主线程上执行,形成一个执行栈,一旦“执行栈”所有同步任务执行完毕,系统才读取“任务队列”

1
2
3
console.log(100);
alert(200); // 一秒钟之后点击确认才继续执行
console.log(300)

这个alert弹框就会阻塞程序,程序是同步进行的。

同步和异步的区别是什么?分别举例子

  • 同步会阻塞代码执行,异步不会

  • alert是同步的,setTimeout是异步的。


setTimeout

下面看一个例子

1
2
3
4
5
6
7
8
9
console.log(1);
setTimeout(function () {
console.log(2)
})
console.log(3);
setTimeout(function(){
console.log(4)
})
console.log(5);

1、3、5、2、4


前端使用异步的场景

  • 在可能发生等待的情况下

  • 等待过程不能像alert一样阻塞程序进行

  • 因此,所需要等待的情况都需要异步
    比如

  • 定时任务:setTimeout,setInterval

  • 网络请求:ajax请求,动态加载。

下面是一个ajax的例子,不会因为ajax请求不到数据而发生阻塞,而是继续执行打印end,然后什么时候请求到了数据再执行回调函数。

1
2
3
4
5
console.log('start);
$.get('./data1.json', function (data1) {
console.log(data1);
})
console.log('end);

下面是一个动态加载图片的例子

1
2
3
4
5
6
7
console.log('start');
var img = document.createElement('img');
img.onload = function () {
console.log('loaded);
}
img.src = '/xxx.png';
console.log('end');

img的src可能请求不到或者需要一段时间请求,那么这个时侯onload不能够阻塞程序进行,程序依然需要往下执行。

  • 事件绑定
1
2
3
4
5
console.log('start');
document.getElementById('btn1').addEventListener('click', function () {
alert('clicked');
})
console.log('end');

有点类似上面的例子,我们并不知道什么时候发生点击事件,所以程序正常向下执行直到点击事件发生再回来执行回调函数。


参考资料:http://www.ruanyifeng.com/blog/2014/10/event-loop.html

2018 年 1月 6日