Event Loop

javascript是单线程语言

那么,你可能要问,javascript为什么是单线程,难道不能实现多线程吗?
这跟历史有关系。javascript从诞生的时候就是单线程,原因大概是不想让浏览器变得太复杂,因为多线程需要共享资源、且有可能会修改彼此的运行结果。试想,假如javascript是多线程的,在一个线程中为某个DOM节点添加了任务,在另一个线程中又将该节点删除了,这就比较尴尬了,最后应该依照哪个结果呢?

但是这并不意味着单线程就是阻塞,实现单线程非阻塞的方法就是事件循环。

同步任务和异步任务

在javascript中,我们将所有的任务大体上分为两类:同步任务和异步任务。

  • 同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
  • 异步任务:异步执行的任务,比如ajax网络请求,setTimeout定时函数等。
    在这里插入图片描述
    同步任务进入主线程,即主执行栈,异步任务进入任务队列,主线程中的任务执行完毕为空时,会去任务队列中读取对应的任务,推入主线程执行。上述过程的不断重复就是事件循环。
宏任务和微任务

上面我们认识到了同步任务和异步任务,知道先执行完主执行栈中的同步任务,然后再执行异步任务,那么问题来了,异步任务中哪个任务被率先推入主执行栈中呢?这就引出了我们的宏任务和微任务。
宏任务由宿主发起,而微任务由javascript自身发起。

什么是宿主?宿主就是js运行的环境。一般是浏览器或者Node.

宏任务

  • script (可以理解为外层同步代码)
  • setTimeout/setInterval
  • UI rendering/UI事件
  • postMessage、MessageChannel
  • setImmediate、I/O(Node.js)

微任务

  • Promise.then
  • MutaionObserver
  • Object.observer(已经废弃;Proxy对象替代)
  • process.nextTick(Node.js)

微任务先执行,宏任务后执行。

async和await

async是异步的意思,await则可以理解为async wait。所以可以理解async就是用来声明一个异步方法,而await是用来等待异步方法执行。
async
async函数返回一个promise对象,下面两种方法是等效的

function f() {
    return Promise.resolve('TEST');
}

// asyncF is equivalent to f!
async function asyncF() {
    return 'TEST';
}

await
正常情况下,await命令后面是一个Promise对象,返回该对象的结果。如果不是Promise对象,就直接返回对应的值。

async function f(){
    // 等同于
    // return 123
    return await 123
}
f().then(v => console.log(v)) // 123

不管await后面跟的是什么,await都会阻塞后面的代码。

练习
async function async1() {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2() {
    console.log('async2')
}
console.log('script start')
setTimeout(function () {
    console.log('settimeout')
})
async1()
new Promise(function (resolve) {
    console.log('promise1')
    resolve()
}).then(function () {
    console.log('promise2')
})
console.log('script end')

答案:script startasync1 startasync2promise1script endasync1 endpromise2settimeout.
答案:
1.首先,console.log('script start')直接执行。
2.遇到setTimeout,推进宏任务
3.执行async1(),首先直接打印async1 start,随后遇到await,执行完async2(),打印出async2,会阻塞之后的代码执行,将之后的任务推入微任务,继续执行同步任务。
4.遇到Promise,执行第一步,打印出promise1,将then()中的任务推入微任务,继续执行同步任务。
5.执行到script end,同步任务结束。
6.查看异步任务队列中是否有微任务(注意是异步任务队列,遵循先进先出),依次执行async1 endpromise2
7.微任务执行结束,继续执行宏任务,打印出settimeout,结束。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值