对于像我这样的新手来说,同步异步,js执行原理,浏览器运行机制都有些模糊不清,但在工作的过程中遇见了许多问题没办法啊,只能去弄清楚。
首先浏览器里面是有多个进程的,每个进程里面又有多个线程。然后每次打开一个页面都会有一个render进程,也就是我们最关心的渲染进程。这个进程里面包括几个重要的线程:GUI渲染线程、js引擎线程、事件触发线程、定时器触发线程、异步http请求线程。
我们通常说js是单线程的,指的就是就是js引擎线程,它是render进程里的主线程,执行js代码。它执行结束前,其他的线程可以处理任务,但是最后都要等待主线程执行结束才能继续后续操作(特别是GUI渲染线程和js引擎线程是互斥的,就是先不执行js引擎线程里的重复操作DOM的代码)。
上面没看懂没关系,你只需要知道render进程里有多个线程,而我们js引擎线程就是我们通常说的主线程和单线程js,进入正题,那么在主线程里是如何执行js代码的呢?
首先你要知道什么是同步任务和异步任务,所谓的同步任务就是按顺序执行的任务,就是我这段代码没执行完后面的代码就不会执行。其中包括容易混淆的for循环等各种循环,以及function等(循环和function里都没有异步任务),看一下以下的例子。
//代码说明
f1(list){
console.log('function',list[0])
console.log('function',list[1])
console.log('function',list[2])
console.log('function',list[3])
}
async onLoad(){
this.baseInfo =storage.get(key.BASE_INFO)
let list = [0,1,2,3]
for(let i=0;i<list.length;i++){
let item = list[i]
console.log('for循环',item)
}
console.log('循环结束')
this.f1(list)
console.log('函数执行结束')
}
那么什么才是我们说的异步任务呢,异步任务就是执行到它,它还没执行完就执行下面的代码了。我知道的任务包括setTimeout、setInterval、还有ajax请求。
尴尬的是,开始的时候我以为Promise对象、async函数都是异步任务,后来才发现,这个是优化异步任务执行的一些操作。就是刚刚说的,异步任务还没执行完就执行下面的代码了,那么如果你需要异步任务的一些执行结果,进行后续的操作,那要怎么办呢?于是就有了Promise、async这样的解决方案。
好了现在来具体说说,这两种分别是如何解决异步任务的令人不舒服的地方的。
//令人不舒服的地方代码说明
Promise,首先你要知道Promise是同步的,它里面执行到异步任务以前都是同步执行的。当执行的异步任务的时候,如ajax请求。它就被挂起了,挂在哪里呢,异步http线程。然后继续执行主线程Promise后面的代码。当这个http请求有结果返回的时候,Promise的状态就改变啦。接着又由事件触发线程(我的猜测),把时间状态扔到消息队列里(任务队列里)。当主线程执行完了,事件触发线程就开始遍历消息队列,然后执行相应时间的后续代码。对于promise而言可以是then()或者catch()。
//promise代码示意
async函数是如何操作的呢?这个是直接把异步任务改成同步任务啦
//宏任务和微任务
setTimeout,setInterval属于宏任务,promise的回调函数属于微任务,主线程执行完后先执行已经完成的微任务,在执行宏任务。