Java异步执行原理_JavaScript 中的异步原理

本文探讨了Java和JavaScript中的异步执行原理,包括事件循环、回调函数、Promise和Generator。异步编程旨在解决代码长时间运行导致的宿主环境假死问题,通过事件循环机制和各种异步处理方式,如回调、Promise和Generator,实现任务的有序调度和执行。
摘要由CSDN通过智能技术生成

原标题:JavaScript 中的异步原理

来源:极链科技

作者:周哲

所谓“异步” ,简单说就是一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。比如,有一个任务是读取文件进行处理,异步的执行过程就是下面这样。

常见的浏览器无响应(假死),往往就是因为某一段 Java 代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。

为了解决这个问题,Java 语言将任务的执行模式分成两种:同步( Synchronous )和异步( Asynchronous )。

450172ed805aae47034bbcd0c0342aa8.png

异步编程原理

Java 引擎负责解析,执行 Java 代码,但它并不能单独运行,通常都得有一个宿主环境,一般如浏览器或 Node 服务器,前文说到的单线程是指在这些宿主环境创建单一线程,提供一种机制,调用 Java 引擎完成多个 Java 代码块的调度,这种机制就称为事件循环( Event Loop )。

关于事件循环流程分解如下:

宿主环境为Java 创建线程时,会创建堆 (heap) 和栈 (stack) ,堆内存储 Java 对象,栈内存储执行上下文;

栈内执行上下文的同步任务按序执行,执行完即退栈,而当异步任务执行时,该异步任务进入等待状态(不入栈),同时通知线程:当触发该事件时(或该异步操作响应返回时),需向消息队列插入一个事件消息;

当事件触发或响应返回时,线程向消息队列插入该事件消息(包含事件及回调);

当栈内同步任务执行完毕后,线程从消息队列取出一个事件消息,其对应异步任务(函数)入栈,执行回调函数,如果未绑定回调,这个消息会被丢弃,执行完任务后退栈;

当线程空闲(即执行栈清空)时继续拉取消息队列下一轮消息(next tick ,事件循环流转一次称为一次 tick )。

47d312d21408655f16f5602568fb64bb.png

很多的队列先后按顺序执行任务就形成了 Event

异步编程实现

1 :回调函数

优点:简单、容易理解和部署。

缺点:不利于代码的阅读和维护,各个部分之间高度耦合( Coupling ),流程会很混乱。

2 : Promise 对象

一个 promise 可能有三种状态:等待( pending )、已完成( fulfilled )、已拒绝( rejected ) ;

6699b5dce2502d87411299d902d33416.png

resolve ,接受一个成功值,传递给绑定的 fulfilled 回调函数中。主要工作是将当前状态变为 fulfilled 状态,同时调用绑定的 fulfilled 回调函数。

reject ,接受一个失败信息,传递给绑定的 rejected 回调函数中。主要工作是将当前状态变为 rejected 状态,同时调用绑定的 rejected 回调函数。

then 方法返回一个 Promise 。它有两个参数,分别为 Promise 在成功和失败情况下的回调函数。

语法:

fdd47eab3d0b1ea35c1d3406cb6b0304.png

f2bfef2d9fe389b8ced6a84173426ba6.png

概括来说 promise 是对异步的执行结果的描述对象。

3 : Generator

Generator 函数是 ES6 提供的一种异步编程解决方案 ,允许函数的暂停和恢复。

异步任务的封装:

65f78007b3a2b129fb43964e57f896b2.png

整个过程类似于,浏览器遇到标识符 * 之后,就明白这个函数是生成器函数,一旦遇到 yield 标识符,就会将以后的函数放入此异步函数之内,待异步返回结果后再进行执行。

更深一步,从内存上来讲:

普通函数在被调用时,JS 引擎会创建一个栈帧,在里面准备好局部变量、函数参数、临时值、代码执行的位置(也就是说这个函数的第一行对应到代码区里的第几行机器码),在当前栈帧里设置好返回位置,然后将新帧压入栈顶。待函数执行结束后,这个栈帧将被弹出栈然后销毁,返回值会被传给上一个栈帧。

当执行到 yield 语句时, Generator 的栈帧同样会被弹出栈外,但 Generator 在这里耍了个花招 —— 它在堆里保存了栈帧的引用(或拷贝)!这样当 it.next 方法被调用时, JS 引擎便不会重新创建一个栈帧,而是把堆里的栈帧直接入栈。因为栈帧里保存了函数执行所需的全部上下文以及当前执行的位置,所以当这一切都被恢复如初之时,就好像程序从原本暂停的地方继续向前执行了。

而因为每次 yield 和 it.next 都对应一次出栈和入栈,所以可以直接利用已有的栈机制,实现值的传出和传入。返回搜狐,查看更多

责任编辑:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值