Chapter 1: Asynchrony: Now & Later

在一门语言中,比如JavaScript, 最重要但仍然常常被误解的编程部分是如何在一个完整的时间周期表示和操作程序行为。

这是关于当你的程序正在部分运行,其他部分等待运行。--这之间的gap。

mind the gap!(比如在subway door and the platform)

异步编程就是这个核心: now and later parts of your program

在JS的发展初级, callback function足够用了。但是JS继续在scope和complexity方向成长,为了满足不断扩展的要求(作为第一类编程语言,它运行在浏览器,服务器,已经每个它们之间的设备),开发者需要更强大的并且合理的功能。

后几章我们会探索各种异步的JS技术。

但此时我们将不得不更深度地理解什么是异步asynchrony, 它如何在JS操作!


A Program in Chunks

可以把JS程序 写在一个.js文件内,不过程序是由不同的部分组成,有的部分现在执行,有的则等待执行。

常见的chunk单位是函数。

比如发送请求并⌛️处理响应的数据。这之间有一个gap, 最简单的等待的方式是使用一个函数,即回调函数:

ajax( "http://some.url.1", function myCallbackFunction(data){

    console.log( data ); // Yay, I gots me some `data`!

} );

再看一个:

function now() {
return 21;
} function later() {
answer = answer * 2;                //黄色部分是later
console.log( "Meaning of life:", answer );
} var answer = now(); setTimeout( later, 1000 ); // Meaning of life: 42

分为立即执行的now chunk, 和1000毫秒(1秒)后的later chunk

setTimeout()建立了一个事件(a timeout)在1秒之后发生。所以later()函数在1秒之后执行。

当你把一段代码放入一个函数并直到它被执行,用来响应某个事件,你正在创建一个later chunk。

因此asynchrony来到了你的程序!

Async Console

注意console.log也是异步的,不同的浏览器consol I/O可能不同导致不同的输出console.log(..)。

所以在debugging时,需要当心!!

var a = {
index: 1
}; // later
console.log( a ); // ?? // even later
a.index++; 这个例子: 有可能console.log(a) 在a.index++执行后,才执行!

注意:debug最好是用断点来代替console.log输出。 或者把问题对象转化为JSON格式(JSON.stringify)


Event Loop

尽管JS允许异步代码,但直到ES6,JS本身没有任何直接的异步概念内建在JS。

The JS engine itself has never done anything more than execute a single chunk of your program at any given moment, when asked to.

The JS engine doesn't run in isolation. It runs inside a hosting environment, which is for most developers the typical web browser.

Over the last several years (but by no means exclusively), JS has expanded beyond the browser into other environments, such as servers, via things like Node.js.

In fact, JavaScript gets embedded into all kinds of devices these days, from robots to lightbulbs.

But the one common "thread" (that's a not-so-subtle asynchronous joke, for what it's worth) of all these environments is that they have a mechanism in them that handles executing multiple chunks of your program over time, at each moment invoking the JS engine, called the "event loop."

so, 比如,当你的JS程序发出Ajax请求向服务器取数据,你在一个函数内建立响应代码(callback),并且JS engine 告诉hosting environment:“喂,我将暂停执行,但是当你完成网络请求,并有数据,请调用回调函数”。

浏览器于是建立监听从网络来的响应,并当它有something给你,它根据时间表安排回调函数,把它插入event loop中执行。

什么是event loop?

伪代码演示:

// `eventLoop` is an array that acts as a queue队列,先排队的先办理
var eventLoop = [ ];
var event; // keep going "forever"
while (true) {
// perform a "tick"
if (eventLoop.length > 0) {
// get the next event in the queue
event = eventLoop.shift(); // now, execute the next event
try {
event();
}
catch (err) {
reportError(err);
}
}
}

持续的运行♻️, 每次迭代(iteration重复)循环被称为,tick!

每一个tick, 如果一个事件在queue中等待,执行它,拿出队列。这些事件就是你的函数回调。

需要重点⚠️:

setTimeout()不会把你的回调函数放到event loop queue中。它只是建立一个timer。当timer expires, 环境会把你的回调放入event loop,等待, 当tick到它,就会执行它。

所以,真实的回调函数发生的时间比setTimeout()设置的时间要多一个等待时间。

⚠️!

ES6改变了event loop queue被管理的模式。ES6明确了event loop 如何工作。这意味着技术上它属于JS engine 的 范围, 而不是hosting environment。

这么做的主要原因在Promises内有介绍。(见第3章),因为需要直接的管理在event loop queue的时间表操作。


Parallel Threading 平行线程

async和parallel是 2个不同的事情。

记住,async是关于现在后之后的这个缺口gap。而parallel是关于事情能够被同步发生。

最普通的parallel计算工具是processes 和 threads。Processes and threads 可以独立地执行,也可以同步地执行。on separate processors, or even separate computers, 但是多个线程可以共享一个单独进程的内存

An event loop, by contrast, breaks its work into tasks and executes them in serial, disallowing parallel access and changes to shared memory. Parallelism and "serialism" can 共存 in the form of cooperating event loops in separate threads.

一个event loop, 不允许parallel access 和改变共享的内存。平行和序列可以在event loop这个合作的event loops形式下在各自的线程内同时存在。

我的理解:

同时执行2个线程,那么共享的内存的数据被这2个线程使用会导致数据混乱,造成结果的不确定。

所以,JS不会共享data across 线程。

Run-to-Completion

JS是单线程的,所以可能是先执行foo,等foo执行完成后,再执行bar。也肯能相反。

var a = 20;

function foo() {
a = a + 1;
} function bar() {
a = a * 2;
} // ajax(..) is some arbitrary Ajax function given by a library
ajax( "http://some.url.1", foo );
ajax( "http://some.url.2", bar );

这样的不确定问题无法解决!

因此,ES6介绍了一个thing,可以指定先执行哪个。

Concurrency并发

an example of event, actions etc happening at the same time!

让我们想象一个网页,它显示一个更新状态的列表,当用户滚动列表时,加载这个列表。为了让这样的功能实现,至少需要2个独立的'processes'被同步地执行。

当用户滚动页面到底部时, 激活第一个‘process1’响应 onscroll事件(发出Ajax请求,请求新的list内容)。

第二个‘process2’将会接收Ajax 响应(用于把数据渲染到网页)。

当用户的滚动足够快,你会看到2个以上的onscroll事件在刚完成第一个响应的返回和处理时就fire了。

比如: 滚动请求4和5,6,发生的足够块,以至于响应4和滚动请求6同时激活。

onscroll, request 1
onscroll, request 2 response 1
onscroll, request 3 response 2
response 3
onscroll, request 4
onscroll, request 5
onscroll, request 6 response 4
onscroll, request 7
response 6
response 5
response 7

并发就是2个或更多的‘processes’在相同的时间段同步的执行,不考虑是否他们的内部的event操作在平行(在相同的一瞬间)发生。你可以认为并发是在‘process’层次的平行(task-level),不是操作层次的平行 (operation-level)。

本例子:

process1在请求1开始,在请求7结束。

process2在响应1开始,在响应7结束。它们是同步执行的(并发concurrency)。

因此就造成了以下可能:

一个滚动时间和一个Ajax响应事件可能在相同的时刻等待被处理。比如请求2和响应1。

但是,JS是单线程的,在event loop queue中,只能一次处理一个事件。

这就造成了不确定性nondeterminism。

于是event loop queue可能是这样排队的:(也可能是另外的排序)

onscroll, request 1   <--- Process 1 starts
onscroll, request 2
response 1 <--- Process 2 starts
onscroll, request 3
response 2
response 3
onscroll, request 4
onscroll, request 5
onscroll, request 6
response 4
onscroll, request 7 <--- Process 1 finishes
response 6            //出错❌了!!!
response 5
response 7 <--- Process 2 finishes

2个process并发运行(task-level parallel),但它们内部的独立事件需要在event loop queue中排队处理。

Noninteracting 不交互

如果两个'process'不会产生交互(互相不干扰),则nondeterminism非确定性可以完全接受。

var res = {};

function foo(results) {
res.foo = results;
} function bar(results) {
res.bar = results;
} // ajax(..) is some arbitrary Ajax function given by a library
ajax( "http://some.url.1", foo );
ajax( "http://some.url.2", bar );

foo, bar互不干扰,谁在event loop queue的前面,无所谓。

Interaction

更常见的,并发"processes"是必须要交互的, 非直接的通过作用域和/或者 DOM。

当如此交互发生 , 你需要coordinate协调这些交互,防止"race conditions",

You Don't Know JS: Async & Performance(第一章, 异步:now & later)的更多相关文章

  1. You Don't Know JS: Async & Performance(第3章, Promises)(未看)

    Chapter 3: Promises But what if we could uninvert that inversion of control? What if instead of hand ...

  2. You Don't Know JS: Async & Performance(第2章,Callbacks)

    Chapter 2: Callbacks. Callbacks are by far the most common way that asynchrony in JS programs is exp ...

  3. Node.js学习(第一章:Node.js安装和模块化理解)

    Node.js安装和简单使用 安装方法 简单的安装方式是直接官网下载,然后本地安装即可.官网地址:nodejs.org Windows系统下,选择和系统版本匹配的.msi后缀的安装文件.Mac OS ...

  4. Node.js学习(第一章:Node.js简介)

    Node.js是什么? Node.js 诞生于 2009 年,由 Joyent 的员工 Ryan Dahl 开发而成, 目前官网最新版本已经更新到 12.0.0版本,最新稳定的是10.15.3.Nod ...

  5. You Don't Know JS: Scope & Closures (第一章:什么是Scope)

    Content What is Scope? Lexical Scope Function Vs. Block Scope Hoisting Scope Closures Appendix: Dyna ...

  6. 《深入浅出Node.js》第4章 异步编程

    @by Ruth92(转载请注明出处) 第4章 异步编程 Node 能够迅速成功并流行起来的原因: V8 和 异步 I/O 在性能上带来的提升: 前后端 JavaScript 编程风格一致 一.函数式 ...

  7. 《深入浅出Node.js》第3章 异步I/O

    @by Ruth92(转载请注明出处) 第3章 异步I/O Node 的基调:异步 I/O.事件驱动.单线程. Node 不再是一个服务器,而是一个可以基于它构建各种高速.可伸缩网络应用的平台. No ...

  8. 【vue.js权威指南】读书笔记(第一章)

    最近在读新书<vue.js权威指南>,一边读,一边把笔记整理下来,方便自己以后温故知新,也希望能把自己的读书心得分享给大家. [第1章:遇见vue.js] vue.js是什么? vue.j ...

  9. 第一章 用three.js创建你的第一个3D场景

    第一章 用three.js创建你的第一个3D场景 到官网下载three.js的源码和示例. 创建HTML框架界面 第一个示例的代码如下: 01-basic-skeleton.html 位于 Learn ...

随机推荐

  1. django基础 -- 2. django初识

    一.模块渲染  jinja2 实现简单的字符串替换(动态页面) 1.下载 pip install jinja2 示例 : html文件中 <!DOCTYPE html> <html ...

  2. selenium css定位方式

  3. Actions对Element的一些操作解析

    针对Chrome浏览器: 在自动化测试的编写中如果报出Element is not visible to click at xxxx point时,我会使用: new Actions(WebDrive ...

  4. topcoder srm 691 div1 -3

    1.给定一个$n$个顶点$n$个边的图,边是$(i,a_{i})$,顶点编号$[0,n-1]$.增加一个顶点$n$,现在选出一个顶点集$M$,对于任意的在$M$中 的顶点$x$,去掉边$(x,a_{x ...

  5. 关于 RabbitMQ 的 Dead-Letters-Queue “死信队列”

      来自一个队列的消息可以被当做‘死信’,即被重新发布到另外一个“exchange”去,这样的情况有: 消息被拒绝 (basic.reject or basic.nack) 且带 requeue=fa ...

  6. CF375D Tree and Queries(dsu on tree)

    思路 dsu on tree的板子,可惜人傻把 for(int i=fir[u];i;i=nxt[i]) 打成 for(int i=fir[u];i<=n;i++) 调了两个小时 这题要求维护& ...

  7. docker 命令2

    docker build -t dvm.adsplatformproxy:v1.0.0 . #build images docker run -e WWNamespace=dev -e ZKServe ...

  8. 利用Spring Cloud实现微服务- 熔断机制

    1. 熔断机制介绍 在介绍熔断机制之前,我们需要了解微服务的雪崩效应.在微服务架构中,微服务是完成一个单一的业务功能,这样做的好处是可以做到解耦,每个微服务可以独立演进.但是,一个应用可能会有多个微服 ...

  9. IIS7.5 错误代码0x8007007e HTTP 错误 500.19 - Internal Server Error

    今天在win2008+IIS7.5的环境中部署WCF服务后,一直出现无法打开的页面.具体错误信息如下: HTTP 错误 500.19 - Internal Server Error 无法访问请求的页面 ...

  10. 【BZOJ】1875: [SDOI2009]HH去散步

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1875 注意的是路径不可以重复,所以这题把边看成点.每一条无向边拆成两条有向边. 令${F[ ...