| 45 | |
| 46 | // 触发依赖 |
| 47 | public trigger() { |
| 48 | if (this.dep.size) { |
| 49 | // forEach每次循环都会调用函数,但是有js引擎层面(解释器)的优化 |
| 50 | this.dep.forEach((cb, path) => { |
| 51 | cb(); |
| 52 | this.oldValMap.delete(path); |
| 53 | }); |
| 54 | this.dep.clear(); |
| 55 | |
| 56 | // for (const [path, cb] of this.dep.entries()) { |
| 57 | // cb(); |
| 58 | // this.oldValMap.delete(path); |
| 59 | // } |
| 60 | |
| 61 | /** |
| 62 | 不使用 for of 原因: |
| 63 | |
| 64 | 一方面for of 内部循环调用迭代器接口(entries()方法实际上返回的就是迭代器,entries()比values()方法更慢),原理类似这样: |
| 65 | // 遍历迭代器 |
| 66 | const iterator = this.dep[Symbol.iterator](); // 获取Map的迭代器接口(迭代器为各种不同的数据结构提供统一的访问机制) |
| 67 | while (true) { |
| 68 | const item = iterator.next(); |
| 69 | if (item.done) break; |
| 70 | ... // 执行功能代码 |
| 71 | } |
| 72 | 但是具体实现可能要比这复杂的多,单纯使用 while 仅遍历 values() 的时候,上面方法是比forEach(key,value都会处理)快的, |
| 73 | (while遍历values()更快,但是遍历entries()比forEach慢,所以使用forEach,另外while遍历迭代器可读性较差) |
| 74 | 而for of 仅遍历values()时也比forEach慢,所以js对于遍历迭代器的执行效率似乎并不高。 |
| 75 | |
| 76 | ...运算符也是同理,一样是通过遍历迭代器实现,性能也一般,例如原生call是比apply快的(以前,或者某些低版本浏览器,现在差距不大了, |
| 77 | 据说是因为apply参数是数组,内部实现时需要处理这个数组有额外消耗),call(this, a, b, c)本来是比apply(this, [a, b, c])性能高或者持平的, |
| 78 | 但是如果非要用call(this, ...[a, b, c]),那就有点画蛇添足了,强行多出来一个遍历迭代器的工作,性能直接变low |
| 79 | |
| 80 | 另一方面,解构也会消耗一定性能(其实内部也是遍历迭代器接口按顺序获取对应的值进行赋值,比正常取值慢2-3倍),所以此处使用forEach, |
| 81 | 仅针对数组解构,对象解构还是通过属性取值,只是换了种写法而已,性能一致。 |
| 82 | */ |
| 83 | } |
| 84 | }; |
| 85 | |
| 86 | // 更新被监听的响应式对象,触发响应式对象的set,收集被监听路径的依赖 |
| 87 | public updateWatchedData(path: string, newVal: any) { |