7-9 Sizzle编译原理(上)
本节编程练习不计算学习进度,请电脑登录imooc.com操作

Sizzle编译原理(上)

一个人去完成一件事情,如果派多个人去做的话,只要配合默契,效率比一个人做肯定要高,效率提高,所需的时间就减少了。如果只能一个人完成,那么必须设法提高自己的劳动效率,这个提高可以是量的改变也可以是质的改变。我把这个量的改变称为空间上的改变,也就是说空间和时间是可以相互转换的。

综合之前我们分析的:

按照解析原理,词法分析,过滤器原理处理之后得到的种子合集通过一次用循环递归去匹配查找,这样的效率是很慢的。

那么sizzle从给1.8开始就引入了编译的概念:

sizzle引入这个编译函数主要的作用是为分词的筛选,提高逐个匹配的效率,实现闭包缓存

闭包是js的特性,我们经常会用来作为私有变量的保存处理,那么sizzle就很好的利用了这一特性,把选择器中每一个选择原子都变成了函数的处理方法,然后通过闭包保存着。再缓存在内存中去,这样有重复使用的时候就会首先调用缓存。

Sizzle对于编译这个最终的过滤器闭包是非常绕的,先通过简单的例子去展示这一个复杂的思路。

具体见右边代码所示:

抛开伪类的处理,这里就是一个简化版的sizzle的流程。

任务

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  5. <script src="http://code.jquery.com/jquery-latest.js"></script>
  6. <title></title>
  7. </head>
  8. <body>
  9.  
  10.  
  11. <button id="test1">模拟编译原理,点击选中checked</button>
  12.  
  13. <div id="text">
  14. <div class="Aaron">
  15. <input type="checkbox" name="readme" />
  16. <input type="checkbox" name="ttt" />
  17. <input type="checkbox" name="aaa" />
  18. <p>Sizzle</p>
  19. </div>
  20. </div>
  21.  
  22.  
  23.  
  24. <script type="text/javascript">
  25.  
  26. var filter = {
  27. ATTR: function(name, operator,check) {
  28. return function(elem) {
  29. var attr = elem.getAttribute(name)
  30. if (operator === "=") {
  31. if(attr === check){
  32. return true
  33. }
  34. }
  35. return false;
  36. }
  37. },
  38. TAG: function(nodeNameSelector) {
  39. return function(elem) {
  40. return elem.nodeName && elem.nodeName.toLowerCase() === nodeNameSelector;
  41. };
  42. }
  43. }
  44.  
  45. function addCombinator(matcher) {
  46. return function(elem, context, xml) {
  47. while ((elem = elem['parentNode'])) {
  48. if (elem.nodeType === 1) {
  49. //找到第一个亲密的节点,立马就用终极匹配器判断这个节点是否符合前面的规则
  50. return matcher(elem);
  51. }
  52. }
  53. }
  54. }
  55.  
  56.  
  57. function elementMatcher(matchers) {
  58. return matchers.length > 1 ?
  59. function(elem, context, xml) {
  60. var i = matchers.length;
  61. while (i--) {
  62. if (!matchers[i](elem, context, xml)) {
  63. return false;
  64. }
  65. }
  66. return true;
  67. } :
  68. //单个匹配器的话就返回自己即可
  69. matchers[0];
  70. }
  71.  
  72.  
  73.  
  74. function matcherFromTokens(tokens){
  75. var len = tokens.length;
  76. var matcher, matchers = [];
  77. for (i = 0; i < len; i++) {
  78. if (tokens[i].type === " ") {
  79. matchers = [addCombinator(elementMatcher(matchers), matcher)];
  80. } else {
  81. matcher = filter[tokens[i].type].apply(null, tokens[i].matches);
  82. matchers.push(matcher);
  83. }
  84. }
  85. return elementMatcher(matchers);
  86. }
  87.  
  88.  
  89. function compile() {
  90. //种子合集
  91. var seed = document.querySelectorAll('input')
  92. //选择器
  93. var selector = "Aaron [name=ttt]";
  94. var elementMatchers = [];
  95. var results = []
  96. var match = [{
  97. matches: ["div"],
  98. type: "TAG",
  99. value: "Aaron"
  100. }, {
  101. type: " ",
  102. value: " "
  103. }, {
  104. matches: ["name", "=", "ttt"],
  105. type: "ATTR",
  106. value: "[name=ttt]"
  107. }]
  108. elementMatchers.push(matcherFromTokens(match));
  109. var matcher, elem;
  110. for (var i = 0; i < seed.length; i++) {
  111. matcher = elementMatchers[0];
  112. var elem = seed[i];
  113. if (matcher(elem)) {
  114. results.push(elem);
  115. break;
  116. }
  117. }
  118.  
  119.  
  120. results[0].checked = 'checked'
  121. }
  122.  
  123.  
  124. $('#test1').click(function() {
  125. compile();
  126. })
  127.  
  128.  
  129.  
  130.  
  131.  
  132. </script>
  133.  
  134. </body>
  135. </html>
下一节