+ 4 мин
+
22K
+

Картинка, конечно, стронгли анрилейтед
+
+ Разные трюки я тестировал на Google Chrome 107.0.5304.107 и Mozilla Firefox 107.0 на Windows 10.
+
+ Чтобы результаты всегда были железно воспроизводимыми, я отключил все С-State’ы, ядра зафиксировал на 5 ГГц.
+
+ У меня 9900К, это Coffee Lake c AVX256, какие оптимизации применит Jit для вашего процессора — я не знаю, результат на вашем компьютере может отличаться от моего, в т.ч. из-за микроархитектуры процессора.
+
+ Скорость парсинга кода тоже входит в бенчмарк, поэтому браузер с быстрым парсером будет впереди.
+
+
+ Есть ли у переменной оверхед?
+
+ Есть ли смысл использовать только dot notation? Какова цена выноса лишней переменной?
+
+
var array = new Array(65535).fill()
+
+
+var a = array.map((x) => x)
+var b = array.map((x) => x)
+var c = array.map((x) => x)
+
+
+var a = array.map((x) => x)
+var b = array.map((x) => x).map((x) => x)
+
+
+var a = array.map((x) => x).map((x) => x).map((x) => x)
+ Чтобы узнать, гоняет ли браузер память туда-сюда, делаем мы
.map на массив длиной 65535 с нулями внутри.
Линк.
+
+
Здесь и далее в качестве единицы измерения на графиках будет указано кол-во выполнений кода в секунду, включая парсинг и компиляцию. Больше — лучше
+
+ Хром не заметил разницы, а вот лиса заметила. Применительно к лисе, у лишней переменной есть измеряемый оверхед.
+
+
+ Есть ли разница между var, let, const или их отсутствием?
+
+
+ Проверим. Используя разные биндинги — создадим POJO с переменной
е. Потом добавим ему функцию
о и запустим эту функцию. Бенчмарк простой, но движущихся частей много.
Линк.
+
+
var g = { e: [] }
+g.o = function(x) { g.e.push(...[1,2,3]) }
+g.o()
+ Код выглядит так, отличаются только биндинги.
+
+
+ Результат неожиданный, но железно воспроизводимый. var, быстрее.
+
+
+ Bounce pattern, Switch case, длинная тернарка
+
+ Если обе конструкции логически одинаковые, они должны строить одно и то же синтаксическое дерево, верно? Давайте проверим.
+
+
+function thing(e) {
+ switch (e) {
+ case 0:
+ return "0";
+
+ case 1:
+ return "1";
+
+ case 2:
+ return "2";
+
+ case 3:
+ return "3";
+
+ default:
+ return "";
+ }
+}
+
+
+function bounce(x)
+{
+ if (x === 0) return "0";
+ if (x === 1) return "1";
+ if (x === 2) return "2";
+ if (x === 3) return "3";
+
+ return ""
+}
+
+
+function bounce(x) {
+ return 0 === x ? "0" : 1 === x ? "1" : 2 === x ? "2" : 3 === x ? "3" : "";
+}
+ Вот так выглядит код. Для всех вариантов он одинаков, отличаются только вызовы.
+
+
+ ▍ 1. Вызов в цикле
+
for (let t = 0; 1e5 > t; t++) bounce(0), bounce(2), bounce(6);
+ Вызов выглядит так.
Линк.
+
+
+
+ ▍ 2. В цикле с другим типом
+
for (let t = 0; 1e5 > t; t++) bounce("0"), bounce("2"), bounce("");
+ Тут мы покидываем строку вместо числа. В свитче и
if блоках используется строгое равенство, поэтому свитч выходит только через
default, а
if’ы выходят только последний
return.
Линк.
+
+
+
+ ▍ 3. Без цикла
+
bounce(0), bounce(2), bounce(6)
+ Просто три вызова подряд, никаких циклов.
Линк.
+
+
+ Похоже, что после первоначальной компиляции лиса не пытается дальше оптимизировать цикл, как это делает хром.
+
+ Также лиса, похоже, не строит одно и то же AST, как это делает хром. Рекомендую заменить ваши длинные
if’ы и bounce паттерны на свитчи, чтобы избежать лисиных тормозов.
+
+
+ Инициализация массива
+
+ Для примера возьму из паттернов функционального программирования, когда ты инициализируешь массив, прокидывая лямбду в инициализатор. Просто ради примера, в качестве этой лямбды будет fizzbuzz.
+
+
var times = 65535;
+
+function initializer(val, z) {
+ const i = z % 5 | 0;
+ return 0 == (z % 3 | 0) ? 0 === i ? "fizzbuzz" : "fizz" : 0 === i ? "buzz" : z;
+}
+
+
+var b = new Array(times);
+for (var i = 0; i < times; i++) {
+ b[i] = initializer(b[i], i)
+}
+b
+
+
+var c = [];
+for (var i = 0; i < times; i++) {
+ c.push(initializer(c[i], i))
+}
+c
+
+
+new Array(times).fill().map(initializer)
+
+ Это не самый красивый fizzbuzz, но это мой fizzbuzz.
Линк на бенч.
+
+
+ Вариант с
fill map создаёт два массива, сначала при вызове конструктора, потом при вызове map. Но такой вариант безальтернативно быстрее на хроме.
+
+
+ Конкатенация массивов
+
+arr.reduce((acc, val) => acc.concat(val), [])
+
+
+arr.flatMap(x => x)
+
+
+arr.flat()
+
+
+arr.reduce((acc, val) => {
+ if (val) val.forEach(a => acc.push(a));
+ return acc;
+}, [])
+
+
+let acc = [];
+
+arr.forEach(val => {
+ val && val.forEach(v => acc.push(v));
+}), acc;
+
+
+[].concat(...arr)
+
+ Конкатенация массивов на 1 уровень, поведение идентичное
flat(1).
Линк.
+
+
+ Иногда я не понимаю, почему разработчики движков оставили такой потенциал для оптимизации.
+
+
+ Уничтожение хрома
+
+ Бенчмарки ниже я перепроверял по нескольку раз, результат одинаковый и верный. Лиса действительно такая быстрая.
+
+
+ ▍ Итерация по массиву
+
+ Сравнивать будем
Array.prototype.forEach vs for...of vs for. На код смотрите
по линку.
+
+
+ Ради производительности, циклы
for, лучше переделать в
forEach, чтобы хром не отставал.
+
+
+ ▍ Содержит ли строка значение
+
+url.includes('matchthis')
+
+
+/matchthis/.test(url)
+
+
+url.match(/matchthis/).length >= 0
+
+
+url.indexOf('matchthis') >= 0
+
+
+url.search('matchthis') >= 0
+
+
+
+ Трюк с
IndexOf быстрее и на лисе, и на хроме. Используйте трюк с
IndexOf.
Линк на бенчмарк.
+
+
+ Преобразование строки в число
+
+ Тестируем неявное преобразование, парсинг и вызов конструктора.
+
+
+var imp = + strNum
+
+
+var toStr = parseFloat(strNum)
+
+
+var num = Number(strNum)
+
+ ▍ Float
+
+
+
+ Я перепроверял, это не ошибка. Неявный каст стринги в инт практически бесплатный у лисы.
Линк на бенч.
+
+
+ Выводы
+
- Лисичка похорошела.
- JS сделан за неделю на коленке.
- Я не пишу на JS.
- Вы тоже прекращайте.
\ No newline at end of file
diff --git a/packages/readabilityjs/test/test-pages/yuyue.com/distiller.html b/packages/readabilityjs/test/test-pages/yuyue.com/distiller.html
new file mode 100644
index 000000000..6ca990185
--- /dev/null
+++ b/packages/readabilityjs/test/test-pages/yuyue.com/distiller.html
@@ -0,0 +1,220 @@
+
+ 一句话,用整体性学习,即把新旧知识链起来成网,而不是分割成一块一块。
+
作者用了三个观点和五个步骤来介绍整体性学习,如下:
+
整体性学习基于三个观点:
+
1、结构
相当于一座座城市,语文是一座,数学是一座。发达的城市,学有关的东西就会很快,例如学表达,写作。聪明人就是把新东西和老城市建立交易,联系越多越容易学,条条大路通新知识。完成自觉建立知识间联系的习惯,很容易学好。也就是说,只要新知识能放进城市里,建立起来联系,那就很容易学。
已经成熟的结构有
●感知结构:眼、鼻、耳、舌、手。最基本的结构,也发展的最好。
●关系结构:各种关系,人人、人事等等。
●基础数学结构:代数、函数等,用来简化其他学科内的关系。
+
2、模型
属于简化的结构,是城市的缩略图,是书的目录。模型的形式不限制,主要是为了压缩信息,将核心概念整合在一起,是城市的地基,最核心的部分,在模型的基础上引申出全部的知识。模型可以是一张图,一句话。后续的新知识在模型的基础上进行联系和优化。模型可以改进和优化,比如用视觉化。
+
3、高速公路
城市之间的连接,例如正在学习生物,将其与熟悉的商业发展史建立联系。高速公路可以激发创造力,将常人眼里风马牛不相及的专业联系在一起,将知识变得更有弹性。
+
整体性学习的五个步骤
+
1、获取
①获取的信息要准确:信息来源尽可能质量高一点。得到、或者比较好的课程。
②信息要简化:废话删掉。用笔记流加适当图表。
(1)不要呆板、僵硬、貌似层次分明的笔记。(2)在写下来的观点之间建立联系。
+
+ STHY IN ONE PAGE
+
+ MESIN ISU'L CESIUNT . NORL REART
+
+ DMHRU
+
+ NHER QUARTILE DANGE
+
+ 189
+
+ 压缩笔记示例
+
+ (第-133
+
+ (一页纸概括了一门课的所有观点)
+
+ VERIANIS
+
+ SHEPIR SUAR SOARY
+
+ 之一部
+
+ LBEEEFFJ
+
+ PGOLUC ING
+
+ AWUNTILE QUTY PERCOATAGE
+
+ HORMAT QUARHILE UIAT
+
+ RE NFENFEAY
+
+ MAOICTBINS!
+
+ VALUE& OF OF.
+
+ SARTPLE
+
+ VERS
+
+ YY RESPONSE
+
+ FIEANCNTY.9RAND
+
+ BLANPLANATORY
+
+ 中国石化
+
+ CERRELATION A 二
+
+ MVHANASG
+
+ WIGHRION
+
+ EFP AINGT BY
+
+ H-!
+
+ QUNER,ENSS
+
+ THABE VED PONIRE
+
+ 王云以
+
+ DESS ANE CENT OFROTPOWE CENE CEN
+
+ LE EST SQVARES GEGSI ON LINE
+
+ 5.5
+
+ LBUT
+
+ 19
+
+ TRAPOIPLEN
+

③容量尽可能大:一年读2本和一年读100本的差别
④速度尽可能快:阅读方法要好,同时不能漏掉太多重点。推荐用指读法。
+
2、理解(停留在这一步就是死记硬背式学习)
①字面意思是什么,每个字母代表什么。
②怎么得来的,和上下文有联系吗。
③如果无法理解,就往更细的点拆分,直至理解。
+
3、拓展
①这才是整体性学习的真正开始,用已有的模型来简化新知识的结构。
②分三种方式
+
+ 知识的背景探究:从何而来,有什么
+
+ 深度拓展(最
+
+ 试验,论据是什么
+
+ 耗时)
+
+ 类似的结论有哪些,异同点是什么,
+
+ 横向拓展
+
+ 同时期的发现有哪些,同领域的发现
+
+ 有哪些
+
+ 在结构间建立高速公路
+
+ (1)为你正在学习的东西创造脑海中的图像.
+
+ 纵向拓展(最
+
+ 难,最具创造
+
+ 较好的方法是,比喻法和内在化
+
+ 内在化即图像化
+
+ (2)在这幅图像上加入其他感官和情感.
+
+ 性)
+
+ (3)寻找图像不适用或不足的地方,防止产生
+
+ 错误的联系
+

4、纠错
①发现一些特例并指出,删除一些现实中不存在的联系,删除错误结论。
②不断实践,搞清楚是概念本身的问题还是理解问题;每种类型都实践下;每天都练练,不要临时突击。
+
5、应用:创造途径,将所学应用到生活中去
+
0、测试:伴随每一步,主要是改进技术
+
+ 获取:我以前看过或听过这个吗
+
+ 理解:我理解知识的含义吗
+
+ 拓展:我知道它从何而来,与哪些知识有联系吗
+
+ -纠错:我删了错误结论以及不恰当的联系吗
+
+ 应用:我将知识应用到实际生活中了吗
+

另外讲了信息的类型
1、随意信息:事实、日期、定义或规则,没逻辑和规律。可以用联想来处理(最弱的信息,最难进行整体性学习,尽可能赋予一点逻辑,在无序中找有序)
2、观点信息:存在争论的信息,用图表法来处理
3、过程信息:教你怎么行动的信息,如游泳,需要不断练习,可以用内在化、比喻法来改进。(强信息,可以直接唤起新旧知识的联系)
4、具体信息:信息和感官可以联系在一起(强信息,可以直接唤起新旧知识的联系)
5、抽象信息:有逻辑,但是没图像,非常抽象(看过《别闹了,费曼先生》,就知道费曼最过人之处就是别人看到的是抽象物理知识,而他看到的是实际生活)
信息处理的精髓即,将弱信息结构转为强信息结构。
+
讲了这样学习的好处
通过联想,所有的观点、知识都会变得有用,尝试将你的课程与感兴趣的东西联系在一起,任何所学知识都要发掘其实际的用处,特别是对于改进自身有什么实际用处。
(1)统计学──我利用统计学知识给本书起名字以及定价。利用谷歌搜索引擎,我尝试各种名字和价格,最终利用统计学决定了这个书名和价格最为吸引人。
(2)计算机──除了编程这种明显的应用之外,我还发现计算机科学是寻找问题的有用途径,纠错、算法都是可以借鉴到其他地方的有用思想。
(3)会计学──会计学能帮助我理清个人财务以及报税。运用基本的会计学原理整理我的个人财务,使它们看起来一目了然。
(4)经济学──经济学教会我重新看待金钱在社会中的价值,明白了金钱仅仅是物质交换的载体后,我的个人哲学体系也随之发生了很多变化。
(5)历史──历史是了解现在的工具,通过学习古代亚洲史能帮助我们看清现代中国、印度和日本的种种问题。历史就是照亮现在的一面镜子。
+
最后讲了如何提高效率
1、能量管理:关于能量管理,最好的一本书是《精力管理:管理精力,而非时间,是高效、健康与快乐的基础》(The Powerof Full Engagement)
2、保持整体性学习的闭环实践,而不是只做其中一部分。
3、不拖延,用周目标和日目标来分配工作
+
+ 这是我的周/日(W/D)目标体系.
+
+ MY LISTS THLS LLST:EDIT I REORDER I SHARS
+
+ 周目标:2月4~10日
+
+ 每周博客更新
+
+ PTB文档
+
+ MY LISTS THIS LIST:EDIT RCORDEE I SHARE
+
+ "FLEX"
+
+ 文档
+
+ 日目标:2008年2月5日
+
+ 网址备份
+
+ 课程
+
+ 阅读周四ENT案例
+
+ 健身
+
+ 阅读下一个周四ENT案例
+
+ 演讲
+
+ 土司马斯
+
+ (TOASTMASTERS)
+
+ 我使用TADALIST,这是一个
+
+ 阅读会计学第5章
+
+ 在线程序.每天晚上我都要检查
+
+ 阅读会计学第5章
+
+ 自己的每日目标和每周目标完成
+
+ 阅读周四ENT案例
+
+ 情况,以确保最终实现目标.
+

4、批量处理:《批处理:节省时间、减轻压力的20个小技巧》。
5、有序:某些物品放在固定位置;有随时记录想法的地方;坚持写清单和日历。
6、养成习惯并每天都坚持:《如何改变一个习惯》(How to Change a Habit)。
+
+ 从智力挑战开始
+
+ 智力挑战的目的是养成新的习惯,许多新方法一开始用起来都很费时间.练
+
+ 习2~4周后,速度和效果会大大提高.最后,你需要根据学习的目标对方法进行适当
+
+ 的改进.
+
+ 以下是一些重要的技巧.
+
+ (1)至少坚持了周.可能你想学会本书介绍的很多技术,但是要记住,如果你不
+
+ 坚持3周以上的智力挑战练习,很难将新技术变成一种习惯.
+
+ (2)一次只做一个.不要试图一次完成几个智力挑战,一次只专注一个.
+
+ (3)比喻,内在化和图表法优先.这些是整体性学习中的核心技术,就从它们
+
+ 开始吧!
+
+ (4)使用奖励材料.本书附赠有6段专门设计用于练习智力挑战的奖励材料,利
+
+ 用它们会让你更轻松些.
+
+ (5)记录下学习的过程.练习智力挑战时,坚持写一句话日记,用一两句话记
+
+ 下你的体会和感受,有助于你坚持下来和解决练习中的各种问题.
+

+
+
\ No newline at end of file