JavaScript单线程和异步机制

Posted 阿柴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript单线程和异步机制相关的知识,希望对你有一定的参考价值。

说到这个异步,首先就要弄懂,什么是同步?我们先来看看,同步和异步的区别在什么地方。 
先来看看一个列子

console.log(100)
setTimeout(function(){
  console.log(200)
},1000)
console.log(300)

打印出来的顺序,100 300 200 
这样子应该看明白了,这个程序是没有阻塞的.. 
一步一步往下执行,先打印出100,然后是是一个setTimeout事件,一秒钟之后打印出200.然后再打印出300.可以函数实际却不是这么执行的。 
这就是一个异步的操作。setTimeout是一个异步的事件。我们来对比看看同步的

console.log(100)
alert(200)
console.log(300)

这就是一个同步的执行过程,首先打印出的100,然后就是弹出一个alert框,你要是一生都不点击确认框,那么这个300就永远也打印不出来。很明显,这就是一个阻塞的过程了 
既然有了异步,那么这种异步的实际应用场合是什么样子的呢? 
一句话,如果不想阻塞后面的操作,那就来一个异步吧。 
主要场景如下 
定时任务:setTimeout setInterval 
网络请求:ajax操作,动态img请求 
事件处理:click等事件 
定时任务本文的一开始就介绍过了,万一是n秒之后呢,难道我要等着你么?想得美! 
看看ajax的网络请求

console.log(100)
$.get(\'../data.json\',function(){
  console.log(200)
})
console.log(300)

这个网络请求,完全是要看网络怎么样,万一请求到了一万年之后,那怎么办?所以咯,我要异步异步异步!!!

console.log(100)
var img=document.createElement(\'img\')
img.onload=function(){
console.log(200)
img.src="../hahhahah.jpg"
}
console.log(200)

这个也是同理的,要是你的图片一直加载不出来,那不好意思,你继续,我先往下进行

console.log(100)
document.getElementById(\'haha\').addEventListener(\'clcik\',function(){
console.log("终于点击了")
})
console.log(200)

鬼知道你什么时候要触发这个点击事件,所以咯,还是一样的哈,啥时候点击了,啥时候执行你。不要影响到别人

难道就没人好奇么?为什么这个js要采取这样子的异步的模式 

这就要说到单线程了,单线程!!!!!!!!!!!!

console.log(100)
setTimeout(function(){
  console.log(200)
})
console.log(300)

先打印出100,然后呢?看到了setTimeout这个函数,哎呀妈呀,这个可是一个异步操作呀,关进小黑屋,先一边呆着去。继续执行,打印出300.好了,程序执行完了,去看看那个黑屋里面的货怎么样了,打印出200

 什么是单线程?意思就是说,一次只能干一个事,就像我们人一样,你能一边学习,一边做饭吗?是同时同步,而不是,我上一秒学习,下一秒做饭,你这个是快速的上下文切换 
还有一种情况,你一边听歌,一边做饭,那好吧,这个谁不会呢?我们这里指的是,你自己有意识的,需要付出心思的同时干两种事情 
程序是单线程的,只能挨个的执行,这个没执行完,下一个免谈,要是碰见了耗时长的任务,如果是多线程的话,还能用另外一个线程来执行,但是单线程的情况下,那你就只能自认倒霉,你就这么耗着吧。 
当然了,人类是聪明的,单线程的春天到了。因为我们想到了异步呀,你不是耗时很长会阻塞么,那你滚吧

那好,我滚了,但是我还是要执行的啊,那我什么时候执行呢? 
这个时候,就要回调来处理 
啥叫回调? 
我的理解就是,你要在某个函数之后调用,不能抢了人家的顺序

function a(){
  console.log("a")
}
function b(fn){
  console.log("b")
  fn()
}
b(a)

像上面的这个函数,是不是我先调用了函数b,然后函数a才能执行啊,那你可以反驳,这样子好麻烦,我直接按顺序不也可以吗。看代码

function b(){
  console.log("b")
}
function a(){
  console.log("a")
}
b()
a()

这样子不也是,先调用了函数b,然后再调用了函数a么?所以,这说明。回调函数真正的用处不在这儿,因为这两种写法没啥子大不了的区别

console.log(100)
setTimeout(function(){
  console.log(200)
},1000)
console.log(300)

那这个例子呢?setTimeout函数被关去了小黑屋,现在轮到他调用了,一秒之后,打印出了200。这就是回调函数的作用啊,100 200都打印出来了之后,又再过了一秒,才轮到这个函数执行,打印出了200

console.log(100)
$.get(\'../data.json\',function(data){
  console.log(data)
})
console.log(300)

看这个网络请求。100 300都打印出来了之后,我去处理这个ajax的请求,请求完了。获取到数据了,我总不能不管了吧,获取的数据总要取出来吧,这个时候,我定义了一个函数,就是用来当请求处理完了之后,用来处理后续的操作的,比如取得请求数据啥的。 
总结:js是一个单线程的,要是遇见耗时的操作,不能白白就这么耗着啊,让这个操作先一边玩去,等我处理完了之后,再去处理这个耗时的操作,当我操作成功之后,用一个回调函数来去处理,至于什么时候请求完成,那就是别的知识点了。这个回调函数具体啥时候执行,就要看你具体是什么操作了

以上是关于JavaScript单线程和异步机制的主要内容,如果未能解决你的问题,请参考以下文章

0182 JavaScript执行机制:单线程,同步任务和异步任务,执行栈,消息队列,事件循环

JavaScript单线程和异步机制

Javascript异步机制

我想这次我真的理解了 JavaScript 的单线程机制

Javascript的异步与单线程

javascript同步和异步的区别与实现方式