JavaScript是单线程,因此同个时间只能处理同个任务
所有任务都需要排队,前一个任务执行完,才能继续执行下一个任务。
但是,如果前一个任务的执行时间很长,比如文件的读取操作或ajax操作,
后一个任务就不得不等着,用户只能在那里干等着,严重影响用户体验。
因此,JavaScript在设计的时候,就已经考虑到这个问题,
主线程可以完全不用等待文件的读取完毕或ajax的加载成功,可以先挂起处于等待中的任务,先运行排在后面的任务,
等到文件的读取或ajax有了结果后,再回过头执行挂起的任务。
因此,任务就可以分为同步任务和异步任务。
1.同步任务
是指在主线程上按顺序依次执行的任务
2.异步任务
异步任务不进入主线程,而是在其等待的时间内被挂起,放入任务队列,(等待时间结束后)当任务队列告知主线程,可以执行异步任务了,该异步任务才会进入主线程。
总的js的异步机制分为如下步骤:
1.所有同步任务都在主线程上执行,形成一个执行栈;
2.异步任务存在于任务队列,当异步任务有结果之后,就会在任务队列中放置一个事件;
3.当执行栈中的同步任务执行完毕后,系统就会读取任务队列,看看里面还有那些事件,进入执行栈执行事件;
4.主线程不断地重复以上三步骤;
3.异步编程的实现
a.回调函数
b.promise对象
<script type="text/javascript">
function fn(){
return new Promise((resolve,reject)=>{
//异步函数
setTimeout(()=>{
console.log('fn异步操作结束');
//执行完成后 调用resolve函数告知外界,异步结束
resolve();
},100);
})
}
fn().then((res)=>{//res表示响应成功的参数
// console.log(res);//res是resolve()函数传回来的,上一个异步操作的结果
console.log('fn第二步');
})
//执行结果: fn异步操作结束
//fn第二步
//eg2 Promise解决回调地狱问题
function fn2(){
return new Promise((resolve)=>{
setTimeout(()=>{
console.log('fn2异步操作结束');
resolve(2);//可以认为是一个标记,表示异步操作完成
},100);
})
}
//解决:
fn().then(()=>{
return fn2();//返回一个promise对象
}).then((res)=>{
console.log(res);
console.log('fn2第二步')
})
//执行结果:
//fn异步操作结束
//fn2异步操作结束
//2
//fn2第二步
</script>
4.补充箭头函数的this指向
<script type="text/javascript">
//箭头函数替换了匿名函数
var obj={
a:10,
say:()=>{
setTimeout(()=>{
//因为此处为箭头函数,所以this由外层函数来决定
//由于其外层函数还是一个箭头函数,所以this指向window
console.log('say():'+this.a);
},100)
},
run:function(){
setTimeout(()=>{
console.log(this.a);
},100)
},
fun(){//es6中对象方法的简写
setTimeout(()=>{
console.log(this.a);
},100)
},
say2:()=>{
console.log('say2():'+this.a);
}
}
obj.say();//undefined
obj.run();//10
obj.fun();//10原理同上
obj.say2();//undefined
</script>
</html>