Web 2.0 时代 (1999)

人与人之间联系更加紧密的互联网

  • “Users were encouraged to provide content, rather than just viewing it.”
  • 你甚至可以找到一些 “Web 3.0”/Metaverse 的线索

是什么成就了今天的 Web 2.0?

  • HTML (DOM Tree) + CSS = 终端世界
    • 通过 JavaScript 可以改变它
    • 通过 JavaScript 可以连接数据中心
    • Ajax (Asynchronous JavaScript + XML) 和 $
  • 例子:Jupyter Notebook

人机交互程序:特点和主要挑战

特点:不太复杂

  • 既没有太多计算
    • DOM Tree 也不至于太大 (大了人也看不过来)
    • DOM Tree 怎么画浏览器全帮我们搞定了
  • 也没有太多 I/O
    • 就是一些网络请求

挑战:程序员多

  • 零基础的人你让他整共享内存上的多线程
  • 恐怕我们现在用的到处都是 bug 吧???
    • 框架:不用怕,有我在
    • AI: 不用怕,有我在

单线程 + 事件模型

尽可能少但又足够的并发

  • 一个线程、全局的事件队列、按序执行 (run-to-complete)
  • 耗时的 API (Timer, Ajax, ...) 调用会立即返回
    • 条件满足时向队列里增加一个事件
$.ajax(
  {
    url: 'https://jyywiki.cn/hello/jyy',
    success: function(resp) {
      console.log(resp);
    },
    error: function(req, status, err) {
      console.log("Error");
    }
  }
);

异步事件模型

好处

  • 并发模型简单了很多
    • 函数的执行是原子的 (不能并行,减少了并发 bug 的可能性)
  • API 依然可以并行
    • 适合网页这种 “大部分时间花在渲染和网络请求” 的场景
      • JavaScript 代码只负责 “描述” DOM Tree

坏处

  • Callback hell (祖传屎山)
    • $.ajax 嵌套 5 层,可维护性已经接近于零了

异步编程:Promise

导致 callback hell 的本质:人类脑袋里想的是 “流程图”,看到的是 “回调”。

The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

Promise: 流程图的构造方法 (Mozilla-MDN Docs)

Promise: 描述 Workflow 的 “嵌入式语言”

Chaining

loadScript("/article/promise-chaining/one.js")
  .then( script => loadScript("/article/promise-chaining/two.js") )
  .then( script => loadScript("/article/promise-chaining/three.js") )
  .then( script => {
    // scripts are loaded, we can use functions declared there
  })
  .catch(err => { ... } );

Fork-join

a = new Promise( (resolve, reject) => { resolve('A') } )
b = new Promise( (resolve, reject) => { resolve('B') } )
c = new Promise( (resolve, reject) => { resolve('C') } )
Promise.all([a, b, c]).then( res => { console.log(res) } )

Async-Await: 一种计算图的描述语言

async function

  • 总是返回一个 Promise object
  • async_func() - fork

await promise

  • await promise - join

A = async () => await $.ajax('/hello/a')
B = async () => await $.ajax('/hello/b')
C = async () => await $.ajax('/hello/c')
hello = async () => await Promise.all([A(), B(), C()])
hello()
  .then(window.alert)
  .catch(res => { console.log('fetch failed!') } )