目录
一、题目
1、同步和异步的区别是什么?分别举一个同步和异步的例子
同步会阻塞代码执行,而异步不会(alert是典型的同步,setTimeout是典型的异步)。
比如说,在同步中遇见alert,如果你不点击弹出框的确定按钮,代码就卡在了这个地方,如果你永远不点击,它就永远不会向下执行,但是异步就不一样,比如setTimeout,它会把异步代码先拿出来,另存起来,然后继续往下执行其他代码,等代码都执行完成之后,再看看内存里是否有另存起来的代码,如果有,再按照要求执行这部分代码。
2、一个关于setTimeout的笔试题
console.log(1)
setTimeout(function (){
console.log(2)
},0);
console.log(3);
setTimeout(function (){
console.log(4)
},1000)
console.log(5)
输出结果 13524
3、前端使用异步的场景有哪些
- 定时任务:setTimeout,setInverval
- 网络请求:ajax请求,动态<img>加载
- 事件绑定
4、异步和单线程的关系
javascript之所以是异步,是因为它是单线程执行的,所以它必须有异步
二、知识点
2.1 什么是异步(对比同步)
js的运行机制就是单线程和异步。js单线程的概念就是一个时间内只能执行一个东西。
- 同步任务的概念。
同步就是发出一个功能调用的时候,在没有得到结果之前,该调用就不返回或者不继续执行后续操作。
同步的典型是alert;刷新页面也是个同步的例子,当我们刷新页面的时候页面会有一个空档期,他是白颜色的,体验不好。同步的例子如下:
console.log(100);
alert(200); //弹出框如果不点击确定就不会继续执行后续操作
console.log(300);
//这个就是同步的例子,如果第二行alert弹出框不点击确定,下面代码就没法执行。
//所以说同步会阻塞下面代码执行,异步不会阻塞。
同步异步最大的区别有没有阻塞程序进行
- 异步任务的概念。
异步与同步是相对的,当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作。当这个调用完成后,一般是通过状态、通知和回调来通知调用者。对于异步的调用,调用的返回并不受调用者控制。
console.log(100);
setTimeout(function(){
console.log(200)
},1000);
console.log(300);
输出结果依次为100,300,200
console.log("A");
setTimeout(function(){
console.log("B");
},100)
while(true){
}
结果是:A
因为setTimeout是异步任务,同步任务while一直在运行,所以不会运行异步任务,所以结果一直是A。
var i;
for(i=0;i<4;i++){
setTimeout(function(){
console.log(i);
},1000) //0跟1000输出的结果都一样
}
结果是:输出四次4
因为主要考虑队列插入的时间,for循环是同步任务,执行0的时候符合小于4,运行setTimeout,它是个异步任务,此时i是0,setTimeout不是直接放到异步队列里,而是先挂起,等等待的时间到了(比如1000毫秒),才放到异步队列里,for循环运行的速度特别快。所以最后setTimeout执行的时候i已经变成4了,输出的就是四个4。
如果是0的时候它也不是0,以前浏览器最小的是10毫秒,现在浏览器规定最小是4毫秒,for循环运行特别快,所以4毫秒之内早都运行完了,所以也是输出的四个4。
注意:要理解哪些语句会放入异步任务队列中。放入异步任务队列的时机。
关于Event Loop事件循环的概念
就是有一个运行栈执行同步任务的,当浏览器遇到一个setTimeout,它会认为是个异步任务,不会放到运行栈里面,浏览器会有一个特定模块,来拿走这个setTimeout,当到了setTimeout时间,会把这个异步任务放到异步队列中,同步执行完了,运行栈中没有要执行的任务了,它就去读异步队列,如果发现异步队列中有,它就把异步队列中的任务放到运行栈中执行。等执行完,运行栈中又空了,它会继续看异步队列中有没有异步任务,如果有,还放到运行栈中执行,一直下去。
2.2 何时使用异步?
- 在可能发生等待的情况
- 等待过程中不能行alert一样阻塞程序运行
- 因此,所有的“等待情况”都需要异步
一句话总结就是需要等待但是又不能阻塞程序的时候需要使用异步
2.3 前端使用异步的场景
异步的设计主要是因为javascript是一个单线程的语言,单线程只允许同时做一件事情,如果同时需要做多个,那其他的需要去旁边排队去
- 定时任务:setTimeout,setInverval
- 网络请求:ajax请求,动态<img>加载
- 事件绑定 比如一个点击事件,我不知道它什么时候点,但是在它点击之前,我该干什么还是干什么。用addEventListener注册一个类型的事件的时候,浏览器会有一个单独的模块去接收这个东西,当事件被触发的时候,浏览器的某个模块,会把相应的函数扔到异步队列中,如果现在执行栈中是空的,就会直接执行这个函数。
- ES6中的Promise
img图片的动态加载异步例子:
console.log("start");
var img=document.createElement_x_x_x_x("img");
img.onload=function(){
console.log("loaded");
}
img.src="/xxx.png";
console.log("end");
结果先输出start 再输出end最后输出loaded
事件绑定的例子:
console.log("start");
var btn1=document.getElementById("btn1");
btn1.addEventListener('click',function(){
console.log("clicked");
})
console.log("end");
结果先输出start再输出end点击按钮之后输出clicked,点击多少次输出多少次clicded
2.4 异步和单线程
javascript之所以是异步,是因为它是单线程执行的,所以它必须有异步
js是一直是单线程的,浏览器才是实现异步的那个家伙。
下面的例子,讲述异步和单线程的执行步骤:
console.log(100);
setTimeout(function(){
console.log(200)
});
console.log(300);