Javascript异步概念

阿里云大学教程

  • Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高
  • Node.js 的每一个 API 都是异步的(也有对应的同步API),并作为一个独立线程运行,使用异步函数调用,并处理并发
  • Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现
  • Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数

自己的理解:

单线程,异步,回调,轮询

  • 首先Js当初被设计为单线程,就是防止同时对DOM修改造成的问题,但是单线程的问题也暴露出来的,就是用户进行IO操作时得等待很长时间
  • 自然而然,异步的概念被提出来了
  • 什么是异步什么是同步呢?
    • (执行栈(执行js代码),事件队列(回调函数放置的地方))
    • 同步指的是按照代码顺序一步步的执行,异步指的是不按照顺序执行的代码,这也是解决单线程问题的核心点
    • 当用户遇到耗时的IO操作时,js主线程会跳过这一步继续向后执行,异步代码则交给浏览器的其他线程进行处理
    • 等待处理完成后就会把异步中的回调函数推入事件队列中,等所有的同步任务被执行栈处理完后,就会查询事件队列
    • 如果事件队列中有需要执行的回调函数,则把它推入执行栈中进行处理,处理完成后再次查询事件队列(任务队列是队列,先进先出)
  • 重复上述步骤的行为,就叫做事件轮询;
  • 回调函数指的是其他线程完成操作后需要执行的js代码块,比如读取文件,在底部线程完成读取文件的耗时操作后,会把数据交给回调函数

Node.js中也是使用上述的机制,才能得以实现高性能的服务器

Node.js中的异步:

  • Nod中有回调函数和events
    • 流程遇到异步后执行的回调函数(触发一次)
    • 和浏览器中的DOM事件类似,注册监听器,触发事件,将回调函数推入任务队列中(本质上也是回调,可以多次触发,和事件进行了绑定)

Node中events核心模块可以实现事件发射器:

const events = require('events')
const eventEmitter = new events.EventEmitter()

eventEmitter.on('listen', () => {
    console.log(`您正在访问网址`)
})

app.get('/', (req, res) => {
    eventEmitter.emit('listen')
    res.setHeader('Content-Type', 'text/plain')
    res.end('hello world')
})
复制代码

注意:单线程是指Javascript解释器是单线程的,但底部可能会用到其他线程 比如异步操作读取文件,Javascript是单线程执行js代码,但底层是用了其他线程来读取文件内容的

回调带来的问题:

回调过多导致代码可读性差,维护性差(回调地狱)
解决方法:

  • Promise,Generator,Async
  • Node.js社区工具:
    • promisify
    • async.series/parallel(async模块)
    • ...

ps:补充(window)

执行栈与事件队列

  • 执行栈:
    • 浏览器的js是有两种执行环境,一种是全局,一种是函数,当js执行时,会生成一个任务栈
    • 任务栈最底层是window执行环境,然后进入函数a后,会生成一个该函数的执行环境,并添加到window执行环境的上层,如果该函数里调用了函数b,则会在a的执行环境上添加b的执行环境,可以继续添加,直到内存溢出
    • 当b函数执行完成后,会退出b的执行环境,这是任务栈中只有window和a的执行环境,a函数执行完成后也会退出a的执行环境,这时任务栈中只剩下window的执行环境
  • 事件队列
    • 当任务栈中的任务执行完毕后,主线程处于空闲状态,这时就会到事件队列中查询是否有回调需要执行,如果有,则把回调推入主线程中执行,生成执行环境,完成后退出执行环境,继续查询事件队列,如此反复形成了事件循环

宏任务,微任务
以上都是宏观角度解释事件循环,其实异步任务之间并不相同,他们的执行优先级有区别,不同的异步任务可以分成两类:

  • 宏任务
  • 微任务

常见的宏任务:setTimeout,setInterval,setImmediate
常见的微任务:new Promise(),new MutaionObserver()

遇到异步任务时,会根据异步事件的类型,分别放入宏任务队列,和微任务队列,当执行栈完成了同步操作后会先查询微任务队列, 当所有微任务队列被一件件完成后,再去执行宏任务队列中的回调函数; (宏任务和微任务依然是先进先出)

这样就能解释下面这段代码的结果:

setTimeout(function () {
    console.log(1);
}, 1000);

setTimeout(function() {
    console.log(4)
}, 0)

new Promise(function(resolve,reject){
    console.log(2)
    resolve(3)
}).then(function(val){
    console.log(val);
})

结果为:
4
2
3
1
复制代码

文章就到此结束了,第一次写作,不足之处请,多多指教

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值