Skip to content

Instantly share code, notes, and snippets.

@otakustay
Last active October 13, 2016 14:25
Show Gist options
  • Select an option

  • Save otakustay/cc2625adeb1a37aca04f4f8f396a743f to your computer and use it in GitHub Desktop.

Select an option

Save otakustay/cc2625adeb1a37aca04f4f8f396a743f to your computer and use it in GitHub Desktop.
Optimistic UI Mechanism

Optimistic UI指当前端进行一个异步(如向服务器发送请求)过程时,不等过程结束就响应界面,典型的如邮箱应用中点击“删除邮件”时,邮件会立刻消失,随后才请求服务器进行真正的删除操作。

Optimistic UI的大致过程为:

  1. 发起异步操作
  2. 预测操作的结果,并进行界面更新
  3. 待异步操作结束后,对界面进行调整

在一个复杂的系统中,异步操作会存在并行和乱序的问题,此时多个“预测操作结果更新界面”和“异步完成后调整界面”以随机的顺序进行,容易导致界面出现错误,因此需要一种机制进行管理。

在本文涉及的策略中,界面通过一个称为State的对象生成,即State相同时,界面一定相同。本文的核心思想是将“异步操作”(后称Promise)和“计算State”(后称Action)分离,难过队列的形式管理State的变化,通过找回旧的State来实现异步结束后的界面调整的同时不引起界面错乱。

每个事件处理函数返回一个[Promise<Action>, Action],前者负责真正更新状态,后者负责产生Optimistic State。

每次应用Optimistic State的时候,记录以下内容:

  1. 标记当前State是Optimistic的
  2. 产生这个Optimistic State的Action
  3. 与这个Optimistic State相关的Promise
  4. 最后一个正式的State

比如有以下顺序:

  1. 初始状态state0,此时队列为[state0]

  2. 开始事件1,产生[Promise<Action11>, Action12]

  3. 应用Action12,此时队列为:

    [
        state0,
        {state1: Action12(state0), Promise<Action11>, Action12, pending: true}
    ]
    

    使用state1更新UI

  4. 开始事件2,产生[Promise<Action21>, Action22]

  5. 取最后的Optimistic State即state1应用Action22,此时队列为:

    [
        state0,
        {state1: Action12(state0), Promise<Action11>, Action12, pending: true},
        {state2: Action22(state1), Promise<Action21>, Action22, pending: true}
    ]
    

    使用state2更新UI

  6. 假设事件2比事件1更早结束,则获取到Action21,使用在队列中Action21所在项之前的最后的Optimistic State即state1并应用Action21,但同时还要保留Action21(因为前面还有未完成的事件,这个状态并不是真正的最终状态),此时队列为:

    [
        state0,
        {state1: Action12(state0), Promise<Action11>, Action12, pending: true},
        {state3: Action21(state1), Promise<Action21>, Action22, pending: false} // 这里变成false了
    ]
    

    使用state3更新UI

  7. 事件1结束,获取到Action11,使用队列中Action11所在项之前最后的Optimistic State,此时没有这样的状态,因此不做任何操作,把Action11相关的项的pending票房为false

    [
        state0
        {state1: Action12(state0), Promise<Action11>, Action12, pending: false}, // 这里也变成false了
        {state3: Action21(state1), Promise<Action21>, Action22, pending: false} // 这里变成false了
    ]
    
  8. 当有第7步(找不到最近的Optimistic State)时,在队列中从头到尾找所有pending为false的,一个一个应用到正式的State上,直到碰到pending为true的停下来,则队列会变成:

    [
        state4: Action21(Action11(state0))
    ]
    

    将state4作为正式State并更新UI

@zbinlin
Copy link

zbinlin commented Oct 13, 2016

你好,想问下关于异步操作失败时的 Action 是否也是在 Promise<Action> 里了?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment