- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章聊聊JavaScript 异步编程史由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
。
早期的 Web 应用中,与后台进行交互时,需要进行 form 表单的提交,然后在页面刷新后给用户反馈结果。在页面刷新过程中,后台会重新返回一段 HTML 代码,这段 HTML 中的大部分内容与之前页面基本相同,这势必造成了流量的浪费,而且一来一回也延长了页面的响应时间,总是会让人觉得 Web 应用的体验感比不上客户端应用.
2004 年,AJAX 即“Asynchronous JavaScript and XML”技术横空出世,让 Web 应用的体验得到了质的提升。再到 2006 年,jQuery 问世,将 Web 应用的开发体验也提高到了新的台阶.
由于 JavaScript 语言单线程的特点,不管是事件的触发还是 AJAX 都是通过回调的方式进行异步任务的触发。如果我们想要线性的处理多个异步任务,在代码中就会出现如下的情况:
我们经常将这种代码称为:“回调地狱”.
。
众所周知,JavaScript 的运行时是跑在单线程上的,是基于事件模型来进行异步任务触发的,不需要考虑共享内存加锁的问题,绑定的事件会按照顺序齐齐整整的触发。要理解 JavaScript 的异步任务,首先就要理解 JavaScript 的事件模型.
由于是异步任务,我们需要组织一段代码放到未来运行(指定时间结束时或者事件触发时),这一段代码我们通常放到一个匿名函数中,通常称为回调函数.
。
前面说过回调函数的运行是在未来,这就说明回调中使用的变量并不是在回调声明阶段就固定的.
这里连续声明了三个异步任务,100毫秒 后会输出变量 i 的结果,按照正常的逻辑应该会输出 0、1、2这三个结果.
然而,事实并非如此,这也是我们刚开始接触 JavaScript 的时候会遇到的问题,因为回调函数的实际运行时机是在未来,所以输出的 i 的值是循环结束时的值,三个异步任务的结果一致,会输出三个 i = 3.
经历过这个问题的同学,一般都知道,我们可以通过闭包的方式,或者重新声明局部变量的方式解决这个问题.
。
事件绑定之后,会将所有的回调函数存储起来,然后在运行过程中,会有另外的线程对这些异步调用的回调进行调度的处理,一旦满足“触发”条件就会将回调函数放入到对应的事件队列(这里只是简单的理解成一个队列,实际存在两个事件队列:宏任务、微任务)中.
满足触发条件一般有以下几种情况:
上面的这些行为发生时,代码中之前指定的回调函数就会被放入一个任务队列中,主线程一旦空闲,就会将其中的任务按照先进先出的流程一一执行。当有新的事件被触发时,又会重新放入到回调中,如此循环,所以 JavaScript 的这一机制通常被称为“事件循环机制”.
可以看到,其运行顺序满足队列先进先出的特点,先声明的先被执行.
。
由于 JavaScript 单线程的特点,定时器其实并不可靠,当代码遇到阻塞的情况,即使事件到达了触发的时间,也会一直等在主线程空闲才会运行.
上面代码中,定时器设置了 300ms 后触发回调函数,如果代码没有遇到阻塞,正常情况下会 300ms后,会输出等待时间.
但是我们在还没加了一个 while 循环,这个循环会在 800ms 后才结束,主线程一直被这个循环阻塞在这里,导致时间到了回调函数也没有正常运行.
。
事件回调的方式,在编码的过程中,就特别容易造成回调地狱。而 Promise 提供了一种更加线性的方式编写异步代码,有点类似于管道的机制.
Promise 在很多语言中都有类似的实现,在 JavaScript 发展过程中,比较著名的框架 jQuery、Dojo 也都进行过类似的实现。2009 年,推出的 CommonJS 规范中,基于 Dojo.Deffered 的实现方式,提出 Promise/A 规范。也是这一年 Node.js 横空出世,Node.js 很多实现都是依照 CommonJS 规范来的,比较熟悉的就是其模块化方案.
早期的 Node.js 中也实现了 Promise 对象,但是 2010 年的时候,Ry(Node.js 作者)认为 Promise 是一种比较上层的实现,而且 Node.js 的开发本来就依赖于 V8 引擎,V8 引擎原生也没有提供 Promise 的支持,所以后来 Node.js 的模块使用了 error-first callback 的风格(cb(error, result)).
这一决定也导致后来 Node.js 中出现了各式各样的 Promise 类库,比较出名的就是 Q.js、Bluebird。关于 Promise 的实现,之前有写过一篇文章,感兴趣可以看看:《手把手教你实现 Promise》.
在 Node.js@8 之前,V8 原生的 Promise 实现有一些性能问题,导致原生 Promise 的性能甚至不如一些第三方的 Promise 库.
所以,低版本的 Node.js 项目中,经常会将 Promise 进行全局的替换:
。
Generator(生成器) 是 ES6 提供的一种新的函数类型,主要是用于定义一个能自我迭代的函数。通过 function * 的语法能够构造一个 Generator 函数,函数执行后会返回一个iteration(迭代器)对象,该对象具有一个 next() 方法,每次调用 next() 方法就会在 yield 关键词前面暂停,直到再次调用 next() 方法.
next() 方法会返回一个对象,对象有两个属性 value、done:
由于生成器函数具有中断执行的特点,将生成器函数当做一个异步操作的容器,再配合上 Promise 对象的 then 方法可以将交回异步逻辑的执行权,在每个 yeild 后面都加上一个 Promise 对象,就能让迭代器不停的往下执行.
我们将上面的逻辑进行一下抽象,让每个 Promise 对象正常返回后,就自动调用 next,让迭代器进行自执行,直到执行完毕(也就是 done 为 true).
这也就是 koa 早期的核心库 co 的实现逻辑,只是 co 进行了一些参数校验与错误处理。通过 generator 加上 co 能够让异步流程更加的简单易读,对开发者而言肯定是阶段欢喜的一件事.
。
async/await 可以说是 JavaScript 异步变成的解决方案,其实本质上就是 Generator & co 的一个语法糖,只需要在异步的生成器函数前加上 async,然后将生成器函数内的 yield 替换为 await.
async 函数将自执行器进行了内置,同时 await 后不限制为 Promise 对象,可以为任意值,而且 async/await 在语义上比起生成器的 yield 更加清楚,一眼就能明白这是一个异步操作.
【编辑推荐】https://mp.weixin.qq.com/s/78wIDHTVFUNZO-Z2jtb9IQ 。
最后此篇关于聊聊JavaScript 异步编程史的文章就讲到这里了,如果你想了解更多关于聊聊JavaScript 异步编程史的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
有多久,没有发过短信了? 1、背景简介 在常规的分布式架构下,「消息中心」的服务里通常会集成「短信」的渠道,作为信息触达的重要手段,其他常用的手段还包括:「某微」、「某钉」、
区块链、低代码、元宇宙、AI智能; 01 【 先来说说背景 】 这个概念由来已久,但是在国内兴起,是最近几年; 低代码即「 Low-Code
目录 1、背景简介 2、订单业务 1、订单体系 2、流程管理 2
1. 相同点 用Python语言编写的源代码文件,其文件后缀是 “.py” 或 “.ipynb”。用Python语言编写的源代码文件,其文件后缀是 “.py” 或 “.ipynb”。 2. 区别
功能简介 闭锁是一种同步工具类,可以延迟线程的进度直到其到达终止状态【CPJ 3.4.2】。闭锁的作用相当于一扇门∶ 在闭锁到达结束状态之前,这扇门一直是关闭的,并且没有任何线程能通过,当到达
高阶函数,英文叫 Higher Order function。一个函数可以接收另外一个函数作为参数,这种函数就叫做高阶函数。 示例: function add(x, 
引文 最近公司项目中使用了 Nuxt 框架,进行首屏的服务端渲染,加快了内容的到达时间 (time-to-content),于是笔者开始了对 Nuxt 的学习和使用。以下是从源码角度对 Nux
什么是游标? 游标(cursor)是一个存储在MySQL服务器上的数据库查询, 它不是一条SELECT语句,而是被该语句检索出来的结果集。在存储了游 标之后,应用程序可以根据需要滚动或浏
流水线工作模型在工业领域内十分常见,它将工作流程分为多个环节,每个环节根据工作强度安排合适的人员数量。良好的流水线设计尽量让各环节的流通率平衡,最大化提高产能效率。 Go 是一门实用性语言,流
1. Spring JDBC Spring JDBC的配置 2. Spring JdbcTemplate的常用方法 execute()
1. 前言 大家好,我是安果! 日常编写的 Python 自动化程序,如果在本地运行稳定后,就可以考虑将它部署到服务器,结合定时任务完全解放双手 但是,由于自动化程序与平台兼
前言 有时候我们会有在需要在网页中写代码或者改代码配置的需求,这个时候就需要用到代码编辑器,常规的代码编辑器有 CodeMirror 和 Monaco Editor, CodeMirror 使用的
前言:模块机制是 Node.js 中非常重要的组成,模块机制使得我们可以以模块化的方式写代码,而不是全部代码都写到一个文件里。我们平时使用的比较多的通过 require 加载模块,但是我们可能不
随着互联网的发展,越来越多的公司摒弃了Hibernate,而选择拥抱了MyBatis。而且,很多大厂在面试的时候喜欢问MyBatis底层的原理和源码实现。 总之,MyBatis几乎成为了Jav
@requestmapping和@getmapping @postmapping的区别 最近学习看一些代码,发现对于发送请求这件事,有的地方用@requestmapping,有的地方用@postm
@RequestParam 和 @PathVariable 注解是用于从request中接收请求的,两个都可以接收参数,关键点不同的是@RequestParam 是从request里面拿取值,而 @
PHP8的Alpha版本,过几天就要发布了,其中包含了不少的新特性,当然我自己认为最重要的还是JIT,这个我从2013年开始参与,中间挫折无数,失败无数后,终于要发布的东东。 不过,今天呢,我不打
引言 我们想要网格的服务发现、路由、熔断降级、负载均衡,这些流量治理都在数据面Envoy中执行才行。Envoy也提供的Filter机制来做这些功能,通常有以下方式: 通过C
我是一名优秀的程序员,十分优秀!