ANode 压缩结构设计

提前将 template 编译成 ANode,可以避免在浏览器端进行 template 解析,提高初始装载性能。ANode 是个 JSON Object,stringify 后体积较大,需要设计一种压缩,让其体积更小,网络传输成本更低。

ANode 压缩,简称 APack

总体设计

设计目标和约束有:

  1. 体积较小
  2. 解压缩过程快

基于以上,基本方案为:

  1. 使用一维 JS Array 作为压缩后的对象。符合 JS 能解析,解压缩过程一次遍历完成。
  2. 对不同类型的节点对象,包含的属性是固定的。通过 {number}head 标识类型,然后依次读取,节点对象中的属性名完全被删除。
  3. 空的数组、对象等值,以 undefined 忽略,数组中形态可能是 [1,,],进一步减少体积。
  4. 自己实现 stringify。JSON 中不包含 undefined 类型,使用 JSON stringify 会把 undefined 输出成 null。
  5. 对于 ANode 中数组类型的值,压缩后第一项为数组长度,然后依次为数组 item。
  6. 泛属性节点(普通属性、双向绑定属性、指令、事件、var)由 {number}head 独立标识。
  7. 根据 ANode 中出现的频度,以 0 和 1 标识模板节点,以 2 标识 普通属性节点,3-32 为表达式节点,33-99 为特殊泛属性节点(双向绑定属性、指令、事件、var)。
  8. bool true 以 1 表示,bool false 以 undefined 表示,compressed 为空

模板节点

文本节点

  • head: 0
  • 编码序: {Node}textExpr
  1. aPack = [,9,,2,3,"Hello ",7,,6,1,3,"name",]
  2. /*
  3. {
  4. "textExpr": {
  5. "type": 7,
  6. "segs": [
  7. {
  8. "type": 1,
  9. "value": "Hello "
  10. },
  11. {
  12. "type": 5,
  13. "expr": {
  14. "type": 4,
  15. "paths": [
  16. {
  17. "type": 1,
  18. "value": "name"
  19. }
  20. ]
  21. },
  22. "filters": []
  23. }
  24. ]
  25. }
  26. }
  27. */

元素节点

  • head: 1
  • 编码序: {string?}tagName, {Array<Node>}propsAndChildren, {Array<Node>?}elses
  1. aPack = [1,"dd",3,38,6,1,3,"list",37,"item",,,6,1,3,"list",,9,,1,7,,6,1,3,"item",,]
  2. /*
  3. {
  4. "directives": {
  5. "if": {
  6. "value": {
  7. "type": 4,
  8. "paths": [
  9. {
  10. "type": 1,
  11. "value": "list"
  12. }
  13. ]
  14. }
  15. },
  16. "for": {
  17. "item": "item",
  18. "value": {
  19. "type": 4,
  20. "paths": [
  21. {
  22. "type": 1,
  23. "value": "list"
  24. }
  25. ]
  26. }
  27. }
  28. },
  29. "props": [],
  30. "events": [],
  31. "children": [
  32. {
  33. "textExpr": {
  34. "type": 7,
  35. "segs": [
  36. {
  37. "type": 5,
  38. "expr": {
  39. "type": 4,
  40. "paths": [
  41. {
  42. "type": 1,
  43. "value": "item"
  44. }
  45. ]
  46. },
  47. "filters": []
  48. }
  49. ]
  50. }
  51. }
  52. ],
  53. "tagName": "dd"
  54. }
  55. */

表达式节点

STRING

  • head: 3
  • 编码序: {string}value
  1. aPack = [3,"Hello"]
  2. /*
  3. {
  4. "type": 1,
  5. "value": "Hello"
  6. }
  7. */

NUMBER

  • head: 4
  • 编码序: {number}value
  1. aPack = [4,10]
  2. /*
  3. {
  4. "type": 2,
  5. "value": 10
  6. }
  7. */

BOOL

  • head: 5
  • 编码序: {bool}value
  1. aPack = [5,1]
  2. /*
  3. {
  4. "type": 3,
  5. "value": true
  6. }
  7. */

ACCESSOR

  • head: 6
  • 编码序: {Array}paths
  1. aPack = [6,1,3,"name"]
  2. /*
  3. {
  4. "type": 4,
  5. "paths": [
  6. {
  7. "type": 1,
  8. "value": "name"
  9. }
  10. ]
  11. }
  12. */

INTERP

  • head: 7
  • 编码序: {bool}original, {Node}expr, {Array<Node>}filters
  1. aPack = [7,,6,1,3,"name",]
  2. /*
  3. {
  4. "type": 5,
  5. "expr": {
  6. "type": 4,
  7. "paths": [
  8. {
  9. "type": 1,
  10. "value": "name"
  11. }
  12. ]
  13. },
  14. "filters": []
  15. }
  16. */

CALL

  • head: 8
  • 编码序: {Node}name, {Array<Node>}args
  1. aPack = [8,6,1,3,"showToast",1,6,1,3,"msg"]
  2. /*
  3. {
  4. "type": 6,
  5. "name": {
  6. "type": 4,
  7. "paths": [
  8. {
  9. "type": 1,
  10. "value": "showToast"
  11. }
  12. ]
  13. },
  14. "args": [
  15. {
  16. "type": 4,
  17. "paths": [
  18. {
  19. "type": 1,
  20. "value": "msg"
  21. }
  22. ]
  23. }
  24. ]
  25. }
  26. */

TEXT

  • head: 9
  • 编码序: {bool}original, {Array<Node>}segs
  1. aPack = [9,,2,3,"Hello ",7,,6,1,3,"name",]
  2. /*
  3. {
  4. "type": 7,
  5. "segs": [
  6. {
  7. "type": 1,
  8. "value": "Hello "
  9. },
  10. {
  11. "type": 5,
  12. "expr": {
  13. "type": 4,
  14. "paths": [
  15. {
  16. "type": 1,
  17. "value": "name"
  18. }
  19. ]
  20. },
  21. "filters": []
  22. }
  23. ]
  24. }
  25. */

BINARY

  • head: 10
  • 编码序: {number}operator, {Node}first, {Node}second
  1. aPack = [10,43,6,1,3,"num",4,1]
  2. /*
  3. {
  4. "type": 8,
  5. "operator": 43,
  6. "segs": [
  7. {
  8. "type": 4,
  9. "paths": [
  10. {
  11. "type": 1,
  12. "value": "num"
  13. }
  14. ]
  15. },
  16. {
  17. "type": 2,
  18. "value": 1
  19. }
  20. ]
  21. }
  22. */

UNARY

  • head: 11
  • 编码序: {number}operator, {Node}expr
  1. aPack = [11,33,6,1,3,"exists"]
  2. /*
  3. {
  4. "type": 9,
  5. "expr": {
  6. "type": 4,
  7. "paths": [
  8. {
  9. "type": 1,
  10. "value": "exists"
  11. }
  12. ]
  13. },
  14. "operator": 33
  15. }
  16. */

TERTIARY

  • head: 12
  • 编码序: {Node}condExpr, {Node}truthyExpr, {Node}falsyExpr
  1. aPack = [12,6,1,3,"exists",6,1,3,"num",4,0]
  2. /*
  3. {
  4. "type": 10,
  5. "segs": [
  6. {
  7. "type": 4,
  8. "paths": [
  9. {
  10. "type": 1,
  11. "value": "exists"
  12. }
  13. ]
  14. },
  15. {
  16. "type": 4,
  17. "paths": [
  18. {
  19. "type": 1,
  20. "value": "num"
  21. }
  22. ]
  23. },
  24. {
  25. "type": 2,
  26. "value": 0
  27. }
  28. ]
  29. }
  30. */

OBJECT

  • head: 13
  • 编码序: {Array<Node>}items
  1. aPack = [13,2,14,3,"key",6,1,3,"key",15,6,1,3,"ext"]
  2. /*
  3. {
  4. "type": 11,
  5. "items": [
  6. {
  7. "name": {
  8. "type": 1,
  9. "value": "key"
  10. },
  11. "expr": {
  12. "type": 4,
  13. "paths": [
  14. {
  15. "type": 1,
  16. "value": "key"
  17. }
  18. ]
  19. }
  20. },
  21. {
  22. "spread": true,
  23. "expr": {
  24. "type": 4,
  25. "paths": [
  26. {
  27. "type": 1,
  28. "value": "ext"
  29. }
  30. ]
  31. }
  32. }
  33. ]
  34. }
  35. */

OBJECT ITEM UNSPREAD

  • head: 14
  • 编码序: {Node}name, {Node}expr
  1. aPack = [14,3,"key",6,1,3,"key"]
  2. /*
  3. {
  4. "name": {
  5. "type": 1,
  6. "value": "key"
  7. },
  8. "expr": {
  9. "type": 4,
  10. "paths": [
  11. {
  12. "type": 1,
  13. "value": "key"
  14. }
  15. ]
  16. }
  17. }
  18. */

OBJECT ITEM SPREAD

  • head: 15
  • 编码序: {Node}expr
  1. aPack = [15,6,1,3,"ext"]
  2. /*
  3. {
  4. "spread": true,
  5. "expr": {
  6. "type": 4,
  7. "paths": [
  8. {
  9. "type": 1,
  10. "value": "ext"
  11. }
  12. ]
  13. }
  14. }
  15. */

ARRAY

  • head: 16
  • 编码序: {Array<Node>}items
  1. aPack = [16,3,17,4,1,17,6,1,3,"two",18,6,1,3,"ext"]
  2. /*
  3. {
  4. "type": 12,
  5. "items": [
  6. {
  7. "expr": {
  8. "type": 2,
  9. "value": 1
  10. }
  11. },
  12. {
  13. "expr": {
  14. "type": 4,
  15. "paths": [
  16. {
  17. "type": 1,
  18. "value": "two"
  19. }
  20. ]
  21. }
  22. },
  23. {
  24. "spread": true,
  25. "expr": {
  26. "type": 4,
  27. "paths": [
  28. {
  29. "type": 1,
  30. "value": "ext"
  31. }
  32. ]
  33. }
  34. }
  35. ]
  36. }
  37. */

ARRAY ITEM UNSPREAD

  • head: 17
  • 编码序: {Node}expr
  1. aPack = [17,4,1]
  2. /*
  3. {
  4. "expr": {
  5. "type": 2,
  6. "value": 1
  7. }
  8. }
  9. */

ARRAY ITEM SPREAD

  • head: 18
  • 编码序: {Node}expr
  1. aPack = [18,6,1,3,"ext"]
  2. /*
  3. {
  4. "spread": true,
  5. "expr": {
  6. "type": 4,
  7. "paths": [
  8. {
  9. "type": 1,
  10. "value": "ext"
  11. }
  12. ]
  13. }
  14. }
  15. */

NULL

  • head: 19
  • 编码序: 无
  1. aPack = [19]
  2. /*
  3. {
  4. "type": 13
  5. }
  6. */

泛属性节点

普通属性

  • head: 2
  • 编码序: {string}name, {Node}expr
  1. aPack = [2,"title",9,,2,3,"Hello ",7,,6,1,3,"name",]
  2. /*
  3. {
  4. "name": "title",
  5. "expr": {
  6. "type": 7,
  7. "segs": [
  8. {
  9. "type": 1,
  10. "value": "Hello "
  11. },
  12. {
  13. "type": 5,
  14. "expr": {
  15. "type": 4,
  16. "paths": [
  17. {
  18. "type": 1,
  19. "value": "name"
  20. }
  21. ]
  22. },
  23. "filters": []
  24. }
  25. ]
  26. }
  27. }
  28. */

NOVALUE 属性

  • head: 33
  • 编码序: {string}name, {Node}expr
  1. aPack = [33,"disabled",5,1]
  2. /*
  3. {
  4. "name": "disabled",
  5. "expr": {
  6. "type": 3,
  7. "value": true
  8. },
  9. "noValue": 1
  10. }
  11. */

双向绑定属性

  • head: 34
  • 编码序: {string}name, {Node}expr
  1. aPack = [34,"value",6,1,3,"name"]
  2. /*
  3. {
  4. "name": "value",
  5. "expr": {
  6. "type": 4,
  7. "paths": [
  8. {
  9. "type": 1,
  10. "value": "name"
  11. }
  12. ]
  13. },
  14. "x": 1
  15. }
  16. */

事件

  • head: 35
  • 编码序: {string}name, {Node}expr, {ObjectAsArray}modifier
  1. aPack = [35,"click",8,6,1,3,"showToast",1,6,1,3,"msg",]
  2. /*
  3. {
  4. "name": "click",
  5. "modifier": {},
  6. "expr": {
  7. "type": 6,
  8. "name": {
  9. "type": 4,
  10. "paths": [
  11. {
  12. "type": 1,
  13. "value": "showToast"
  14. }
  15. ]
  16. },
  17. "args": [
  18. {
  19. "type": 4,
  20. "paths": [
  21. {
  22. "type": 1,
  23. "value": "msg"
  24. }
  25. ]
  26. }
  27. ]
  28. }
  29. }
  30. */

var

  • head: 36
  • 编码序: {string}name, {Node}expr
  1. aPack = [1,"dd",1,36,"name",6,2,3,"user",3,"name"]
  2. /*
  3. {
  4. "directives": {},
  5. "props": [],
  6. "events": [],
  7. "children": [],
  8. "tagName": "dd",
  9. "vars": [
  10. {
  11. "name": "name",
  12. "expr": {
  13. "type": 4,
  14. "paths": [
  15. {
  16. "type": 1,
  17. "value": "user"
  18. },
  19. {
  20. "type": 1,
  21. "value": "name"
  22. }
  23. ]
  24. }
  25. }
  26. ]
  27. }
  28. */

指令 for

  • head: 37
  • 编码序: {string}item, {string?}index, {string?}trackByRaw, {Node}value
  • 注: trackBy 通过 trackByRaw 二次解析
  1. aPack = [1,"li",2,37,"item",,,6,1,3,"list",,9,,1,7,,6,1,3,"item",]
  2. /*
  3. {
  4. "directives": {
  5. "for": {
  6. "item": "item",
  7. "value": {
  8. "type": 4,
  9. "paths": [
  10. {
  11. "type": 1,
  12. "value": "list"
  13. }
  14. ]
  15. }
  16. }
  17. },
  18. "props": [],
  19. "events": [],
  20. "children": [
  21. {
  22. "textExpr": {
  23. "type": 7,
  24. "segs": [
  25. {
  26. "type": 5,
  27. "expr": {
  28. "type": 4,
  29. "paths": [
  30. {
  31. "type": 1,
  32. "value": "item"
  33. }
  34. ]
  35. },
  36. "filters": []
  37. }
  38. ]
  39. }
  40. }
  41. ],
  42. "tagName": "li"
  43. }
  44. */

指令 if

  • head: 38
  • 编码序: {Node}value
  1. aPack = [1,"h2",2,38,6,1,3,"title",,9,,1,7,,6,1,3,"title",,]
  2. /*
  3. {
  4. "directives": {
  5. "if": {
  6. "value": {
  7. "type": 4,
  8. "paths": [
  9. {
  10. "type": 1,
  11. "value": "title"
  12. }
  13. ]
  14. }
  15. }
  16. },
  17. "props": [],
  18. "events": [],
  19. "children": [
  20. {
  21. "textExpr": {
  22. "type": 7,
  23. "segs": [
  24. {
  25. "type": 5,
  26. "expr": {
  27. "type": 4,
  28. "paths": [
  29. {
  30. "type": 1,
  31. "value": "title"
  32. }
  33. ]
  34. },
  35. "filters": []
  36. }
  37. ]
  38. }
  39. }
  40. ],
  41. "tagName": "h2"
  42. }
  43. */

指令 elif

  • head: 39
  • 编码序: {Node}value
  1. aPack = [1,"h2",2,38,6,1,3,"name",,9,,1,7,,6,1,3,"name",,1,1,"b",2,39,6,1,3,"shortname",,9,,1,7,,6,1,3,"shortname",]
  2. /*
  3. {
  4. "directives": {
  5. "if": {
  6. "value": {
  7. "type": 4,
  8. "paths": [
  9. {
  10. "type": 1,
  11. "value": "name"
  12. }
  13. ]
  14. }
  15. }
  16. },
  17. "props": [],
  18. "events": [],
  19. "children": [
  20. {
  21. "textExpr": {
  22. "type": 7,
  23. "segs": [
  24. {
  25. "type": 5,
  26. "expr": {
  27. "type": 4,
  28. "paths": [
  29. {
  30. "type": 1,
  31. "value": "name"
  32. }
  33. ]
  34. },
  35. "filters": []
  36. }
  37. ]
  38. }
  39. }
  40. ],
  41. "tagName": "h2",
  42. "elses": [
  43. {
  44. "directives": {
  45. "elif": {
  46. "value": {
  47. "type": 4,
  48. "paths": [
  49. {
  50. "type": 1,
  51. "value": "shortname"
  52. }
  53. ]
  54. }
  55. }
  56. },
  57. "props": [],
  58. "events": [],
  59. "children": [
  60. {
  61. "textExpr": {
  62. "type": 7,
  63. "segs": [
  64. {
  65. "type": 5,
  66. "expr": {
  67. "type": 4,
  68. "paths": [
  69. {
  70. "type": 1,
  71. "value": "shortname"
  72. }
  73. ]
  74. },
  75. "filters": []
  76. }
  77. ]
  78. }
  79. }
  80. ],
  81. "tagName": "b"
  82. }
  83. ]
  84. }
  85. */

指令 else

  • head: 40
  • 编码序: 无
  • 注: 为保持一致,自生成 {value:{}}
  1. aPack = [1,"h2",2,38,6,1,3,"name",,9,,1,7,,6,1,3,"name",,1,1,"span",2,40,,3,"noname"]
  2. /*
  3. {
  4. "directives": {
  5. "if": {
  6. "value": {
  7. "type": 4,
  8. "paths": [
  9. {
  10. "type": 1,
  11. "value": "name"
  12. }
  13. ]
  14. }
  15. }
  16. },
  17. "props": [],
  18. "events": [],
  19. "children": [
  20. {
  21. "textExpr": {
  22. "type": 7,
  23. "segs": [
  24. {
  25. "type": 5,
  26. "expr": {
  27. "type": 4,
  28. "paths": [
  29. {
  30. "type": 1,
  31. "value": "name"
  32. }
  33. ]
  34. },
  35. "filters": []
  36. }
  37. ]
  38. }
  39. }
  40. ],
  41. "tagName": "h2",
  42. "elses": [
  43. {
  44. "directives": {
  45. "else": {
  46. "value": {}
  47. }
  48. },
  49. "props": [],
  50. "events": [],
  51. "children": [
  52. {
  53. "textExpr": {
  54. "type": 1,
  55. "value": "noname"
  56. }
  57. }
  58. ],
  59. "tagName": "span"
  60. }
  61. ]
  62. }
  63. */

指令 ref

  • head: 41
  • 编码序: {Node}value
  1. aPack = [1,"x-item",1,41,9,,2,3,"item",7,,6,1,3,"i",]
  2. /*
  3. {
  4. "directives": {
  5. "ref": {
  6. "value": {
  7. "type": 7,
  8. "segs": [
  9. {
  10. "type": 1,
  11. "value": "item"
  12. },
  13. {
  14. "type": 5,
  15. "expr": {
  16. "type": 4,
  17. "paths": [
  18. {
  19. "type": 1,
  20. "value": "i"
  21. }
  22. ]
  23. },
  24. "filters": []
  25. }
  26. ]
  27. }
  28. }
  29. },
  30. "props": [],
  31. "events": [],
  32. "children": [],
  33. "tagName": "x-item"
  34. }
  35. */

指令 bind

  • head: 42
  • 编码序: {Node}value
  1. aPack = [1,"x-info",1,42,6,1,3,"user"]
  2. /*
  3. {
  4. "directives": {
  5. "bind": {
  6. "value": {
  7. "type": 4,
  8. "paths": [
  9. {
  10. "type": 1,
  11. "value": "user"
  12. }
  13. ]
  14. }
  15. }
  16. },
  17. "props": [],
  18. "events": [],
  19. "children": [],
  20. "tagName": "x-info"
  21. }
  22. */

指令 html

  • head: 43
  • 编码序: {Node}value
  1. aPack = [1,"u",1,43,6,1,3,"text"]
  2. /*
  3. {
  4. "directives": {
  5. "html": {
  6. "value": {
  7. "type": 4,
  8. "paths": [
  9. {
  10. "type": 1,
  11. "value": "text"
  12. }
  13. ]
  14. }
  15. }
  16. },
  17. "props": [],
  18. "events": [],
  19. "children": [],
  20. "tagName": "u"
  21. }
  22. */

指令 transition

  • head: 44
  • 编码序: {Node}value
  1. aPack = [1,"x-item",1,44,8,6,1,3,"trans",]
  2. /*
  3. {
  4. "directives": {
  5. "transition": {
  6. "value": {
  7. "type": 6,
  8. "name": {
  9. "type": 4,
  10. "paths": [
  11. {
  12. "type": 1,
  13. "value": "trans"
  14. }
  15. ]
  16. },
  17. "args": []
  18. }
  19. }
  20. },
  21. "props": [],
  22. "events": [],
  23. "children": [],
  24. "tagName": "x-item"
  25. }
  26. */

指令 is

  • head: 45
  • 编码序: {Node}value
  1. aPack = [1,"u",1,45,6,1,3,"cmpt"]
  2. /*
  3. {
  4. "directives": {
  5. "is": {
  6. "value": {
  7. "type": 4,
  8. "paths": [
  9. {
  10. "type": 1,
  11. "value": "cmpt"
  12. }
  13. ]
  14. }
  15. }
  16. },
  17. "props": [],
  18. "events": [],
  19. "children": [],
  20. "tagName": "u"
  21. }
  22. */