首先我放在文章的开头,重点说两点:javascript
好了,那么咱们开始这篇文章的主要内容,既然说js 是单线程,那就是在执行代码的时候是从上往下执行的,咱们来看一段代码吧:java
setTimeout(function(){
console.log('定时器开始')
});
new Promise(function(resolve){
console.log('Promise开始');
resolve();
}).then(function(){
console.log('执行then函数')
});
console.log('代码执行结束');
复制代码
看到上面的代码,可能你们给出的答案是:'定时器开始','Promise开始','执行then函数','代码执行结束'。那么咱们验证一下,输出结果倒是:ios
看到这样的答案,咱们仍是研究一下他的执行机制吧,至于预解析我后面会单独发一篇文章单独说,这里我们就主要看后面的执行机制了,咱们说JavaScript是一个单线程语言,那他的 "多线程" 是咋来的,都是模拟出来的,一会咱们来看看这个"多线程的纸老虎"。ajax
既然是单线程,那么咱们能够想到,好比去银行办理业务,到了那里要去排队一个一个办理,一样的JavaScript的任务也是一个一个执行,若是前面一个用时很长,那后面哪个就得等着,等到前面的执行完再继续。如今咱们在打开某一个网站的时候,一般会看到有些图片加了背景图,由于页面中有些图片,视频,大批量的数据很是耗时,若是网速很差的电脑去打开,那想而知,空白啦~因此有了如今的 同步 和 异步!~axios
axios.post('/user', { name: 'fly', age: '30' })
.then(function (response) {
console.log(response);
})
console.log('代码执行结束');
复制代码
相信setTimeout你们并不陌生,在工做中可能也会用到,异步函数,还能延迟执行~promise
setTimeout(() => {
console.log('执行setTimeout');
},3000)
console.log('执行console');
复制代码
按照咱们前面的思路,先执行console.log('执行console');而后执行console.log('执行setTimeout');答案没错,那再变换一下:浏览器
setTimeout(() => {
abc();
},3000)
exercise(100000000);//假设有个运动函数,须要时间很长...并且不固定...大于3秒,可能10秒
复制代码
那么咱们在运行结果,发现3秒后并无执行console.log('执行setTimeout');bash
上面的流程走完,咱们知道setTimeout这个函数,是通过指定时间后,把要执行的任务(本例中为abc())加入到Event Queue中,又由于是单线程任务要一个一个执行,若是前面的任务须要的时间过久,那么只能等着,致使真正的延迟时间远远大于3秒。有时候咱们会看到这样的形式setTimeout(function(),0); 0秒是否是当即就执行了呢?其实并非多线程
那他的意识是说,不须要多少秒进入Event Queue ,待主线程任务走完,就回去执行。 仍是刚才的例子:异步
setTimeout(() => {
abc();
},0)
console.log('执行console');
// 1.执行console 2.abc()
复制代码
这里说一下,其实看到有笔者说,setTimeout有最小时间间隔限制,HTML5标准为4ms,小于4ms按照4ms处理,可是每一个浏览器实现的最小间隔都不一样。 setInterval的最短间隔时间是10毫秒,也就是说,小于10毫秒的时间间隔会被调整到10毫秒。这里先记下吧。
两个定时器兄弟,原理同样,只不过setInterval会每隔指定的时间将注册的函数置入Event Queue。若是前面的任务时间过长,也会等待,不过这里注意一点,若是其余的函数执行时间过长,定时器会执行完毕会把这些任务从时间列表拿到事件队列,若是时间唱的函数执行后,超出了延时执行的时间,那么就会挨个的拿到主程序执行,看不出延时时间了。
这里简单说一下Promise的做用,细节就很少说了(还须要总结好多...),Promise对象是用于异步操做的。在实际的开发中,咱们是否是会遇到这种状况:
$.ajax({
url:www.javascript.com,
data:data,
success:() => {
console.log('第一个数据返回成功!');
$.ajax({
url:www.javascript.com,
data:data,
success:() => {
console.log('第二个数据返回成功!');
...若是还有再继续
}
})
}
})
复制代码
看到这段代码,应该不陌生吧,相信你们必定遇到过,"看着还不错,挺好的~~~"!我信你个gui,糟老头子坏得很~,那如今Promise派上用场了:
function abc(url,param){
return new Promise(function (resolve, reject) {
request(url, param, function(){
resolve('数据请求成功了');
}, reject);
});
}
abc.then(function(data){
console.log(date);//'第一个数据请求成功了';
return new Promise(function (resolve, reject) {
request(url, param, function(){
resolve('数据请求成功了');
}, reject)
});
}).then(function(){
console.log(date);//'第二个数据请求成功了';
});
复制代码
这里不过多说Promise 的用法了,继续咱们的正题,除了广义的同步任务和异步任务,咱们对任务有更精细的定义:
不一样类型的任务会进入对应的事件队列Event Queue,好比setTimeout和setInterval会进入相同的Event Queue。 Promise和process.nextTick会进入相同的。
setTimeout(function() {
console.log('setTimeout');
})
new Promise(function(resolve) {
console.log('promise');
resolve();
}).then(function() {
console.log('then');
})
console.log('console');
复制代码
执行结果为:promise,console,then,setTimeout
事件循环,宏任务,微任务的关系如图(这里看到不少做者用到的一张图,我也那过来吧,谢谢图片做者):
那下面就拿到一段代码了,在网上也能看到:
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
附上输出结果:1,7,6,8,2,4,3,5,9,11,10,12
复制代码
在此要感谢网上看到的各位做者的文章(重点看到的csdn,子晓),以为写的很不错,这里也仿照着来记录一下,也加了一下本身见解,但愿能给更多的人带来帮助~~~