JavaScript异步基础

唯一比不知道代码为什么崩溃更可怕的事情是,不知道为什么一开始它是工作的!

在 ECMA 规范的最近几次版本里不断有新成员加入,尤其在处理异步的问题上,更是不断推陈出新。然而,我们在享受便利的同时,也应该了解异步到底是怎么一回事。

现在与将来

JavaScript 是单线程的,一次只能专注于一件事。如果浏览器只靠 JavaScript 引擎线程来完成所有工作,先不说能不能搞定,即使可以,那也会花费很长时间。幸好在浏览器里 JavaScript 引擎并不孤单,还有 GUI 渲染线程、事件触发线程、定时触发器线程、异步http请求线程等其它线程。这些线程之间的协作才有了我们看到的浏览器界面效果(远不止这些)。

(盗了一张图)
thread

一个程序在执行过程中可能会有等待用户输入、从数据库或文件系统中请求数据、通过网络发送并等待响应,或是以固定时间间隔执行重复任务(比如动画)等情况。(这些情况,当下是无法得出结果的,但是一旦有了结果,我们知道需要去做些什么。)

JavaScript 引擎不是一个人在战斗,它把以上的任务交给其它线程,并计划好任务完成后要做的事,JavaScript 引擎又可以继续做自己的事了。从这里可以看出,一个程序的运行包括两部分,现在运行和将来运行。而现在运行和将来运行的关系正是异步编程的核心。

let params = {type:'asynchronous'}
let response = ajax(params,'http://someURL.com'); // 异步请求
if (!response) throw '无数据!';

以上代码肯定会抛错的,异步请求任务交出去之后,程序会继续运行下去。由于ajax(...) 是异步操作,即使立刻返回结果,当下的 response 也不会被赋值。一个是现在,一个是将来,两者本就不属于一个时空的。

事件循环

现在和将来是相对的,等将来的时刻到了,将来也就成为了现在。

JavaScript 引擎运行在宿主环境中,宿主环境提供了一种机制来处理程序中多个块的执行,且执行每个块时调用 JavaScript 引擎,这种机制被称为事件循环。即,JavaScript 引擎本身并没有时间的概念,只是一个按需执行 JavaScript 任意代码片段的环境。

“事件”(JavaScript 代码执行)调度总是由包含它的环境进行。

点击图片进入或点此进入:
EventLoop

一个 JavaScript 运行时包含了一个待处理的消息队列。每一个消息都关联着一个用以处理这个消息的函数。
在事件循环期间的某个时刻,运行时从最先进入队列的消息开始处理队列中的消息。为此,这个消息会被移出队列,并作为输入参数调用与之关联的函数。

while (queue.waitForMessage()) {queue.processNextMessage();
}

一旦有事件需要进行,事件循环就会运行,直到队列清空。事件循环的每一轮称为一个 tick。用户交互,IO 和定时器会向事件队列中加入事件。

(又盗了一张图)
thread

任务队列

任务队列(job queue)建立在事件循环队列之上。(Promise 的异步特性就是基于任务。)

最好的理解方式,它是挂在事件循环队列的每个tick之后的一个队列。在事件循环的每个tick中,可能出现的异步动作不会导致一个完整的新事件添加到事件循环队列中,而会在当前 tick 的任务队列末尾添加一个项目(一个任务)。
即,由 Call Stack 生成的任务队列会紧随其后运行。

Promise.resolve().then(function promise1 () {console.log('promise1');
})
setTimeout(function setTimeout1 (){console.log('setTimeout1');Promise.resolve().then(function  promise2 () {console.log('promise2');})
}, 0)setTimeout(function setTimeout2 (){
console.log('setTimeout2');Promise.resolve().then(function  promise3 () {console.log('promise3');setTimeout(function setTimeout3 () {console.log('setTimeout3');})Promise.resolve().then(function promise4 () {console.log('promise4');})})
}, 0)
// promise1
// setTimeout1
// promise2
// setTimeout2
// promise3
// promise4
// setTimeout3

异步回调

被作为实参传入另一函数,并在该外部函数内被调用,用以来完成某些任务的函数,称为回调函数。回调函数经常被用于继续执行一个异步完成后的操作,它们被称为异步回调。立即执行的称之为同步回调。

回调函数是事件循环“回头调用”到程序中的目标,队列处理到这个项目的时候会运行它。

回调是 JavaScript 语言中最基础的异步模式。

生活中,我们喜欢和有条理的人打交道,因为我们的大脑习惯了这种思维模式。然而回调的使用打破了这种模式,因为代码的嵌套使得我们要在不同块间切换。嵌套越多,逻辑越复杂,我们也就越难理解和处理代码,尤其在表达异步的方式上。

(又盗了一张图)
回调地狱

除了嵌套的问题,异步回调还存在一些信任问题。

  • 回调性质的不确定
  • 调用回调方式不确定(没调用,重复调用等)
  • ......

针对第一点的建议是:永远异步调用回调,即使就在事件循环的下一轮,这样,所有回调都是可预测的异步调用了。
在理解这个建议之前,我们首先了解下控制反转,控制反转就是把自己程序一部分的执行控制交个某个第三方。

let a = 0; // A
thirdparty(() => {console.log('a', a);    // B
})
a++;    // C

A 和 C 是现在运行的,B 虽然代码是我们的,但是却受制于第三方,因为我们无法确定它是现在运行还是将来运行的。这里的回调函数可能是同步回调也可能是异步回调。a 是 0 还是 1,都有可能。

// 同步回调
const thirdparty = cb => {cb();
}
// 异步回调
const thirdparty = cb => {setTimeout(() => cb(), 0);
}

所以,永远异步调用回调,可预测。

function asyncify(fn) {let func = fn;let t = setTimeout(() => {t = null;if (fn) fn();}, 0);fn = null;return () => {if (t) {fn = func.bind(this, ...arguments);} else {func.apply(this, arguments);}}
}let a = 0;
thirdparty(asyncify(() => {console.log('a', a);
}))
a++;
// 1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/536949.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flutter、ReactNative、uniapp对比

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

多线程中ThreadLocal的使用

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

注解版poi操作工具

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

Kali Linux 2019.1 发布,Metasploit 更新到 5.0 版本

百度智能云 云生态狂欢季 热门云产品1折起>>> Kali Linux 2019.1 发布了,Kali 前身 BackTrack,它是一个基于 Debian 的 Linux 发行版,主要用于信息安全行业,其包含了一系列安全、渗透测试和取证工具。此版本 Linux 内核…

peewee mysql_scrapy中利用peewee插入Mysql

前两天老大布置一个任务,说爬下来的数据要存入数据库中,丢给我一个peewee,说用这个。当时的我两眼一抹黑,这是个什么东西呀,我知道scrapy的数据存入数据库是在pipelines中进行设置但是peewee是什么东西呢。经过两天不懈…

Java版数据结构与算法——线性表

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

基于 CODING 的 Spring Boot 持续集成项目

本文作者:CODING 用户 - 廖石荣 持续集成的概念 持续集成(Continuous integration,简称 CI)是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每…

Mybatis组成部分

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

一年java工作经验-面试总结

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

linux mysql python包_03_mysql-python模块, linux环境下python2,python3的

---恢复内容开始---1、Python2 正常[rootIP ~]#pip install mysql-pythonDEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 wont be maintained after that date. A future version of pip will drop …

两年Java工作经验应该会些什么技术

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

centos 6 mysql 5.7.13 编译安装_Centos 6.5 下面 源码编译 安装 Mysql 5.7.13

安装软件依赖包yum -y install gcc gcc-c ncurses ncurses-devel cmake下载软件包cd /usr/local/srcwget https://downloads.mysql.com/archives/get/file/mysql-5.7.13.tar.gz --no-check-certificate下载 boost 库,MySQL 5.7.5 开始Boost库是必需的cd /usr/loca…

LeetCode 237. 删除链表中的节点(Python3)

题目: 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。 现有一个链表 -- head [4,5,1,9],它可以表示为: 示例 1: 输入: head [4,5,1,9], node 5 输出: [4,1,9…

一年Java经验应该会些什么

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

mysql查询各类课程的总学分_基于jsp+mysql的JSP学生选课信息管理系统

运行环境: 最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。IDE环境: Eclipse,Myeclipse,IDEA都可以硬件环境: windows 7/8/10 2G内存以上(推荐4G,4G以上更好)可以实现: 学生,教师角色的…

三年java经验应该会什么?

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

python加法运算符可以用来连接字符串并生成新字符串_中国大学MOOCPython语言入门网课答案...

中国大学MOOCPython语言入门网课答案表达式int(40.5)的值为____________。表达式160.5的值为____________________。python程序只能使用源代码进行运行,不能打包成可执行文件。python语句list(range(1,10,3))执行结果为___________________。pip命令也支持扩展名为.…

全是满满的技术文档

*************************************话不多说-先上教程 ********************************** 完整躺赚教程(不需任何技术,照做就能赚钱):点击此处获取 提取码&#xff1a;6666 被动收入教程(需要一定的技术,会搭建服务器,会发布项目<教程里面会教你>):点击此处获取 提…

JavaScript面试的完美指南(开发者视角)

2019独角兽企业重金招聘Python工程师标准>>> 摘要&#xff1a; 面试季手册。 原文&#xff1a;javascript 面试的完美指南(开发者视角)作者&#xff1a;前端小智Fundebug经授权转载&#xff0c;版权归原作者所有。 为了说明 JS 面试的复杂性&#xff0c;首先&#x…

windows qt 不能debug_linux配置vlc-qt

vlc-qt 是基于vlc库&#xff0c;用于开发音频视频应用&#xff0c;性能优秀。vlc-qt/vlc-qt​github.com使用vlc-qt首先需要编译vlc-qt &#xff08;windows可以下载使用编译好的&#xff0c;但是只能用在release模式&#xff09;&#xff08;在windows系统中&#xff09;使用w…