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. topcoder srm 415 div1

    problem1 link 每次贪心地从crans由大到小地找到一个能搬得动地尽量大地box即可. problem2 link 首先,$hava$可以全部换成钱,然后就是找到一个最小的钱减去自己已有的 ...

  3. uniGUI试用笔记(一)

    通过向导创建一个uniGUI应用服务器,工程中有三个文件: TUniServerModule = class(TUniGUIServerModule) TUniMainModule = class(T ...

  4. linux基础之网络基础配置

    基础命令:ifconfig/route/netstat,ip/ss,nmcli 一.ifconfig/route/netstat相关命令 1.  ifconfig - configure a netw ...

  5. 【做题】CF196E. Opening Portals 排除无用边&最小生成树

    题意:给出一个有\(n\)个结点,\(m\)条边的连通无向图,边有边权,等于经过这条边所需的时间.有\(k\)个点设有传送门.一开始,所有传送门关闭.你从\(1\)号点出发,每当你到达一个有传送门的点 ...

  6. 比较好的一些 ConcurrentHashMap讲解博客

    jdk8 https://blog.csdn.net/jianghuxiaojin/article/details/52006118#commentBox jdk7.8 https://crossov ...

  7. HashMap 和 HashTable 的区别

    1. 存储结构 HashMap HashTable 数组 + 链表/红黑树 数组 + 链表 HashMap的存储规则: 优先使用数组存储, 如果出现Hash冲突, 将在数组的该位置拉伸出链表进行存储( ...

  8. website for .Net Core

    5 Ways to Build Routing in ASP.NET Core Bundling in .NET Core MVC Applications with BundlerMinifier. ...

  9. 5+ App开发打包指南

    HTML5 Plus应用概述 HTML5 Plus移动App,简称5+App,是一种基于HTML.JS.CSS编写的运行于手机端的App,这种App可以通过扩展的JS API任意调用手机的原生能力,实 ...

  10. async函数对比Generator函数

    首先定义一个读取文件的异步函数 var readFile = function(fileName){ return new Promise((resolve,reject)=>{ fs.read ...