JS基础知识7(异步和单线程)

同步与异步

Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。
“同步模式" :后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的
"异步模式":程序的执行顺序与任务的排列顺序是不一致的、异步的。

事件循环:JS 会创建一个类似于 while (true) 的循环,每执行一次循环体的过程称之为 Tick。每次 Tick 的过程就是查看是否有待处理事件,如果有则取出相关事件及回调函数放入执行栈中由主线程执行。待处理的事件会存储在一个任务队列中,也就是每次 Tick 会查看任务队列中是否有需要执行的任务。

任务队列:异步操作会将相关回调添加到任务队列中。而不同的异步操作添加到任务队列的时机也不同,如 onclick, setTimeout, ajax 处理的方式都不同,这些异步操作是由浏览器内核的 webcore 来执行的,webcore 包含上图中的3种 webAPI,分别是 DOM Binding、network、timer模块。
onclick 由浏览器内核的 DOM Binding 模块来处理,当事件触发的时候,回调函数会立即添加到任务队列中。
setTimeout 会由浏览器内核的 timer 模块来进行延时处理,当时间到达的时候,才会将回调函数添加到任务队列中。
ajax 则会由浏览器内核的 network 模块来处理,在网络请求完成返回之后,才将回调添加到任务队列中。
何时需要异步
1.在可能发生等待的情况下(定时任务,网络请求,事件绑定)
js是单线程语言,浏览器只分配给js一个主线程,用来执行任务(函数),但一次只能执行一个任务,这些任务形成一个任务队列排队等候执行,但前端的某些任务是非常耗时的,比如网络请求,定时器和事件监听,如果让他们排队等待执行的话,执行效率会非常的低,甚至导致页面的假死。所以,浏览器为这些耗时任务开辟了另外的线程,主要包括http请求线程浏览器定时触发器浏览器事件触发线程,这些任务是异步的。
使用异步的场景
“异步模式" 非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。在服务器端,"异步模式"甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有http请求,服务器性能会急剧下降,很快就会失去响应。
主要包括
1 http请求线程

console.log("start");
 var img=document.createElement("img");
 img.function(){
   console.log("loaded");
 }
 img.src="https://ps.ssl.qhimg.com/sdmt/75_135_100/t01525fd8d9773b149f.jpg";
 document.body.append(img);
 console.log("end");//执行顺序是 start end loaded 图片的加载时异步的

2 浏览器定时触发器
在这里插入图片描述
结果为首先输出first,然后输出second.setTimeout 设置的是异步任务,会放在 macrotask 里面,等待执行栈的代码执行完毕之后才会执行 macrotask 里面的异步任务,所以这里会等待 for 循环执行完毕才会执行定时器设置的任务。

setTimeout(function () { while (true) { } }, 1000);
setTimeout(function () { alert('end 2'); }, 2000);
setTimeout(function () { alert('end 1'); }, 100);
alert('end');

执行的结果是弹出’end’、’end 1’,然后浏览器假死,就是不弹出‘end 2’
3 浏览器事件触发线程(监听函数有:on,bind,listen,addEventListener,observe)

console.log("start");
 document.getElementById("btn").addEventListener("click",function(){
   console.log("clicked");
 });
 console.log("end"); //执行顺序是start ,end 如果点击才执行clicked 如果不点永远不执行 也是异步的

单线程

异步,放一边,等所有执行完以后,发现,有一个在等着,然后把它拎回去。单线程的特点,不能同时干两件事。

js异步加载的方式

1.设置defer属性,延迟加载脚本(延迟到页面加载为止,按照script标签顺序执行)
2.设置async属性,异步加载脚本(脚本一旦可用,就异步执行,不按照script标签顺序执行)
3.动态创建script标签,页面渲染完成后,执行回调函数

异步加载和延迟加载

异步加载:
1.设置defer属性,延迟加载脚本(延迟到页面加载为止,按照script标签顺序执行)
2.设置async属性,异步加载脚本(脚本一旦可用,就异步执行,不按照script标签顺序执行)
3.动态创建script标签,页面渲染完成后,执行回调函数
延迟加载:
在页面初始化的时候,有些js代码不需要立即执行,此时可以延时加载。例如惰性单例模式。

阻塞与非阻塞

同步会阻塞,异步不会阻塞

javascript和css阻塞

JS阻塞

所有浏览器在下载JS的时候,会阻止一切其他活动,比如其他资源的下载,内容的呈现等等。
直到JS下载、解析、执行完毕后才开始继续并行下载其他资源并呈现内容。
为了提高用户体验,新一代浏览器都支持并行下载JS,但是JS下载仍然会阻塞其它资源的下载(例如.图片,css文件等)。
由于浏览器为了防止出现JS修改DOM树,需要重新构建DOM树的情况,所以就会阻塞其他的下载和呈现。嵌入JS会阻塞所有内容的呈现,而外部JS只会阻塞其后内容的显示,2种方式都会阻塞其后资源的下载。也就是说外部样式不会阻塞外部脚本的加载,但会阻塞外部脚本的执行。

CSS阻塞

CSS本来是可以并行下载的,在什么情况下会出现阻塞加载了(在测试观察中,IE6下CSS都是阻塞加载)
当CSS后面跟着嵌入的JS的时候,该CSS就会出现阻塞后面资源下载的情况。而当把嵌入JS放到CSS前面,就不会出现阻塞的情况了。
根本原因:因为浏览器会维持html中css和js的顺序,样式表必须在嵌入的JS执行前先加载、解析完。而嵌入的JS会阻塞后面的资源加载,所以就会出现上面CSS阻塞下载的情况。

扫描二维码关注公众号,回复: 5644133 查看本文章

嵌入JS应该放在什么位置?

1、放在底部,虽然放在底部照样会阻塞所有呈现,但不会阻塞资源下载。
2、如果嵌入JS放在head中,请把嵌入JS放在CSS头部。
3、使用defer(只支持IE)anysc W3C
4、不要在嵌入的JS中调用运行时间较长的函数,如果一定要用,可以用setTimeout来调用

Javascript无阻塞加载具体方式

将脚本放在底部。还是放在head中,用以保证在js加载前,能加载出正常显示的页面。

猜你喜欢

转载自blog.csdn.net/weixin_43836308/article/details/88423951