js基础-异步,同步,单线程

mac2022-06-30  25

js执行环境是‘单线程’

什么是单线程(single thread)?

指一次只能完成一件任务。

如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推

 

好处:实现起来比较简单,执行环境相对单纯;

坏处:只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。

常见的浏览器无响应(假死),往往就是因为某一段Javascript代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。

 

为了解决单线程这问题,Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)

 

同步模式:

1)前一个任务完成后,执行下一个任务。

2)程序的执行顺序与任务的排列顺序是一致的、同步的;

 

异步模式:

1)前一个任务结束后,不是执行后一个任务,而是执行回调函数,

     后一个任务不等前一个任务结束就执行

2)程序的执行顺序与任务的排列顺序是不一致的、异步的

 

简言之:同步会堵塞代码执行,而异步不会。

 

js异步运行机制之微任务和宏任务

异步执行的运行机制如下(同步任务也如此,因为它可以被视为没有异步任务的异步执行):

  1.所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)

 

  2.主线程之外,还存在一个“任务队列”,只要异步任务有了运行结果,就在“任务队列”之中放置一个事件

 

  3.一旦“执行栈”中的所有同步任务执行完毕,系统就会读取“任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待,进入执行栈,开始执行

 

  4.主线程不断重复第3步

 

微任务和宏任务

macro-task(宏任务):包括整体代码script,setTimeout,setInterval

micro-task(微任务):Promise,process.nextTick

任务队列:宏任务队列 、微任务队列

不同类型的任务会进入不同的任务队列(Event Queue)

事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。

然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务。

 

例子1:

1 setTimeout(function() { 2 console.log('setTimeout'); 3 }) 4 5 new Promise(function(resolve) { 6 console.log('promise'); 7 //resolve(); 8 }).then(function() { 9 console.log('then'); 10 }) 11 12 console.log('console');

 结果:promise console setTimeout

说明:

1 整段代码作为宏任务进入主线程 2 遇到settimeout,将其回调函数注册后分发到宏任务Event Queue。 3 遇到了Promise,new Promise立即执行,then函数分发到微任务Event Queue 4 遇到console.log(),立即执行 5 第一个宏任务执行结束,看看有什么微任务,发现有then,执行 6 第二轮循环,发现宏任务settimeout的回调函数,执行。 7 结束。

例子2:

1 console.log('1'); 2 3 setTimeout(function() { 4 console.log('2'); 5 process.nextTick(function() { 6 console.log('3'); 7 }) 8 new Promise(function(resolve) { 9 console.log('4'); 10 //resolve(); 11 }).then(function() { 12 console.log('5') 13 }) 14 }) 15 process.nextTick(function() { 16 console.log('6'); 17 }) 18 new Promise(function(resolve) { 19 console.log('7'); 20 //resolve(); 21 }).then(function() { 22 console.log('8') 23 }) 24 25 setTimeout(function() { 26 console.log('9'); 27 process.nextTick(function() { 28 console.log('10'); 29 }) 30 new Promise(function(resolve) { 31 console.log('11'); 32 //resolve(); 33 }).then(function() { 34 console.log('12') 35 }) 36 }) 结果:1,6,7,2,3,4,9,10,11

例子3:例子2升级版

1 console.log('1'); 2 3 setTimeout(function() { 4 console.log('2'); 5 process.nextTick(function() { 6 console.log('3'); 7 }) 8 new Promise(function(resolve) { 9 console.log('4'); 10 resolve(); 11 }).then(function() { 12 console.log('5') 13 }) 14 }) 15 process.nextTick(function() { 16 console.log('6'); 17 }) 18 new Promise(function(resolve) { 19 console.log('7'); 20 resolve(); 21 }).then(function() { 22 console.log('8') 23 }) 24 25 setTimeout(function() { 26 console.log('9'); 27 new Promise(function(resolve) { 28 console.log('11'); 29 resolve(); 30 }).then(function() { 31 console.log('12') 32 }) 33 }) 结果 :1,6,7,8, 2,3,4,5, 9,11,12

同步场景

如:alert()  prompt()

 

**前端使用异步场景

在可能发生等待的情况

  1).定时任务:setTimeout setInterval

  2).网络请求:ajax请求,动态<img>加载

  3).事件绑定:addEventListener

例子1:

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

  结果:100 300 200

例子2:

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

     结果:img开始  img结束  loaded

例子3:

1 console.log('事件开始!'); 2 var btn1 = document.getElementById('btn1'); 3 btn1.addEventListener('click',function(){ 4 console.log('你点击我了');//点击了才会显示 5 }) 6 console.log('事件结束!!');

  结果:事件开始!  事件结束! 你点击我了

例子4:

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

  结果:   1 3 5 4 2   //根据封禁时间解封

 

转载于:https://www.cnblogs.com/lingXie/p/11493925.html

最新回复(0)