js中的同步与异步执行顺序

放在前面

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

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

(2)主线程之外,还存在一个"任务队列"(task
queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。

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

(4)主线程不断重复上面的第三步。

注:setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。

通用公式

同步>异步>回调

举个例子


for (var i = 0; i < 9; i++) {
  setTimeout( function(){
        console.log(i);
  }
  ,1000)
}
console.log(i);

先执行同步再执行异步最后执行回调,for循环先执行,每个i都将setTimeOut回调扔到消息队列中,接着执行后面的同步console.log,此时i=9,到此同步执行完毕,回消息队列执行回调,9个setTimeOut依次执行,999999999.


let a = new Promise(function (resolve, reject) {
  console.log(1);
  setTimeout(function () {
    console.log(2)
  },0)
  resolve(true);
}).then(function () {
  console.log(3);
});
console.log(4);
 // 1432

a变量是一个Promise,我们知道Promise是异步的,是指他的then()和catch()方法,Promise本身还是同步的,所以这里先执行a变量内部的Promise同步代码。(同步优先)
所以1先出现,遇到setTimeOut回调放到消息队列中,resolve(true),调用.then中函数放到消息队列中,最后的console.log是同步操作,所以此时出现14,同步这就执行完了。异步从消息队列里出来也就是.then,最后回调也从消息队列出来,所以顺序为1432


new Promise((resolve, reject) => {    
        setTimeout(() => {
            console.log("1111")
        }, 1000)
        resolve()
    }).then(() => {
        console.log('Hello')
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('2222')
            }, 1000)
            resolve()
        }).then(() => {
            console.log('hello vue')
        })
    })
    new Promise((resolve, reject) =>{
        setTimeout(() => {
            console.log('3333')
        }, 1)
        resolve('Hello World!')
    } ).then((data) => {
        console.log(data)
    })
    console.log('我是同步')

上面这个例子:我们按照写的顺序把上面三个setTimeOut分别叫做S1,S2和S3, 三个,then叫做T1, T2, T3
遇到S1放到消息对列中,resolve函数调用T1放到消息队列中,遇到S3,放到消息队列中,resolve函数调用T3放到消息队列中
遇到同步console.log打印我是同步,同步执行完毕
回到消息队列,此时消息队列中有S1, S3, T1, T3, 按照之前提到的setTimeOut会在任务队列队尾执行,所以先执行T1, 打印Hello, 遇到S2放到任务队列中,遇到resolve调用T2放到消息队列中。执行T3 打印Hello World,执行T2,打印hello vue。现在可以执行setTimeOut了,S3延迟1ms执行,所以S3的打印结果3333,先出来然后是S1 1111, S2 2222。
打印顺序是:
我是同步
Hello
Hello World!
hello vue
3333
1111
2222