集千篇理论精华,感悟对同步和异步的理解

核能气质少年 提交于 2019-12-03 23:48:40

一、promise本身是同步还是异步呢?

众所周知,Promise是ES6提出的解决异步编程导致陷入回调地狱问题的,那么Promise是同步的还是异步的?可以确定的是,Promise本身是同步的,而他的.then和.catch为异步的。

举个栗子:
console.log(1)
let a = new Promise((res,rej) => {
   console.log(2);
});
console.log(3);
let b = new Promise((res,rej) => {
    console.log(4);
});
console.log(5);                  //1,2,3,4,5

 二、返回的异步代码执行顺序 (.then / .catah)

console.log(1)
let a = new Promise((res,rej) => {
    console.log(2);
    res();
});
console.log(3);
let b = new Promise((res,rej) => {
    console.log(4);
    res();
});
console.log(5);
a.then(() => {   //先执行a,是因为.then是一个微任务,而且a最先进入微任务队列,所以现在执行a,在执行b,但都必须是在等到同步代码结束之后在进入执行队列;
    console.log(6)
})
b.then(() => {
    console.log(7)
})栗子:
new Promise( ( resolve, reject ) => {
  console.log( "promise1" )
  resolve()
} )
.then( () => {
  console.log( 1 )
} )
.then( () => {
  console.log( 2 )
} )
.then( () => {
  console.log( 3 )
} )

new Promise( ( resolve, reject ) => {
  console.log( "promise2" )
  resolve()
} )
.then( () => {
  console.log( 4 )
} )
.then( () => {
  console.log( 5 )
} )
.then( () => {
  console.log( 6 )
} )

promise1
promise2

1
4
2
5
3
6

 三、宏任务与微任务

- JS是一种单线程语言,代码执行顺序(同步代码先执行---->等同步代码执行完毕异步代码在执行)主线任务清空之后,异步进入任务队列,开始从任务队列进入到主线程。
- 异步任务里面又存在宏任务和微任务。(同步代码不存在宏任务与微任务一说)
- 宏任务:定时器  /   **script**。
- 微任务:.then

 

<script>
        console.log('start');     //同步

        setTimeout(()=>{      //宏任务
            console.log('time1');
        })

        new Promise((resolve)=>{
            console.log('promise');   //同步
            resolve();
        })
        .then(()=>{               //.then是异步   微任务
            console.log('then');
        })

        setTimeout(()=>{     // 宏任务
            console.log('time2');
        })

        console.log('外部console');    //同步
        
        </script>
        执行顺序:
        1、首先同步代码先依次执行;
          star,promise 外部console
        2、then,第一个宏任务下的微任务,
        3、time1  time2  宏任务

 

注意:在下一个宏任务开始之前,必须将当前主线微任务全部执行完毕,才进入下一个宏任务,也就是所谓的事件循环---eventloop。

                                          

 

 

 

三、async和await函数

async 函数是什么?一句话,它就是 Generator 函数的语法糖,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。

async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。

进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

 

注意,await之后的代码必须等await语句执行完成后(包括微任务完成),才能执行后面的,也就是说,只有运行完await语句,才把await语句后面的全部代码加入到微任务行列,所以,在遇到await promise时,必须等await promise函数执行完毕才能对await语句后面的全部代码加入到微任务中,所以,

在等待await Promise.then微任务时,

1.运行其他同步代码,

2.等到同步代码运行完,开始运行await promise.then微任务,

3.await promise.then微任务完成后,把await语句后面的全部代码加入到微任务行列,

4.根据微任务队列,先进后出执行微任

 

 

console.log(1)
async function async1(){
    console.log('async1 start')
    await async2()           //在此先做返回,将后面所有的代码放到异步队列,
    console.log('async1 end')
  }
async function async2(){
    console.log('async2')
}
async1();
console.log('i am koala')//结果:

1
async1 start
async2
i am koala
async1 end

 

  async 函数返回一个 Promise 对象,(promise 本身为同步代码)

当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句

 

async function t1() {
  console.log(1)
  console.log(2)
  await new Promise(resolve => {
    setTimeout(() => {
      console.log('t1p')
      resolve()
    }, 5000)
  })
  await console.log(3)
  console.log(4)
}

async function t2() {
  console.log(5)
  console.log(6)
  await Promise.resolve().then(() => console.log('t2p'))
  console.log(7)
  console.log(8)
}

t1()
t2()

console.log('end')

1
2
5
6
end
t2p
7
8
t1p
3
4

 

 

 

async function async1() {
  console.log( 'async1 start' ) 
  await async2()
  console.log( 'async1 end' )
}
async function async2() {
  console.log( 'async2' )
}
console.log( 'script start' )    //属于一个同步代码,优先于async返回的promise执行,在async内部!
setTimeout( function () {
  console.log( 'setTimeout' )
}, 0 )
async1();
new Promise( function ( resolve ) {
  console.log( 'promise1' )
  resolve();
} ).then( function () {
  console.log( 'promise2' )
} )
console.log( 'script end' )//执行结果

script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout

 

 

 

async function t1 () {
  console.log(1)                               //1
console.log(2)                                //2
  new Promise( function ( resolve ) {             
  console.log( 'promise3' )              //3
  resolve();
  } ).then( function () {
  console.log( 'promise4' )
  } )
  await new Promise( function ( resolve ) {       //如果它等到的是一个 promise 对象,await 也会暂停async后面的代码,先执行async外面的同步代码,
                                                  //等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果
  console.log( 'b' )                    //4

  resolve();
  } ).then( function () {
  console.log( 't1p' )
  } )
  console.log(3)                  
  console.log(4)                  
  new Promise( function ( resolve ) {
  console.log( 'promise5' )      
  resolve();
  } ).then( function () {
  console.log( 'promise6' )
  } )
  }
  setTimeout( function () {
  console.log( 'setTimeout' )
  }, 0 )

  async function t2() {
  console.log(5)
  console.log(6)
  await Promise.resolve().then(() => console.log('t2p'))  //属于promise方法,不是对象!
  console.log(7)
  console.log(8)
  }
  t1()
  new Promise( function ( resolve ) {
  console.log( 'promise1' )       //同步代码
  resolve();
  } ).then( function () {
  console.log( 'promise2' )
  } )
  t2()

  console.log('end');//执行结果;

1
2
promise3
b
promise1
5
6
end
promise4
t1p
promise2
t2p
3
4
promise5
7
8
promise6
setTimeout

 

 分析:

 

 当遇见第一个await之后,阻止后面的承誉德执行,加入微任务队列;执行其他同步代码,但是5,6先于end之前执行,是因为t2在end之前调用。

 

 

总结:await后面如果等到的是promise对象,执行完resolve之后,阻止后面程序的运行,加入微任务队列,如果是promise方法,也就是不是promise对象的时候,同样也阻止后面的程序的运行,也加入微任务队列。

 

 

 

 

 

 

 

 

要有最平凡的生活,和最遥远的梦想,即使明天天寒地冻,路遥马亡……

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!