【深度】扒开V8引擎的源码,我找到了你们想要的前端算法(下次面试官再问算法,用它怼回去!)

算法对于前端工程师来说总有一层神秘色彩,这篇文章通过解读V8源码,带你探索`Array.prototype.sort`函数下的算法实现。

来,先把你用过的和听说过的排序算法都列出来:

* 快速排序
* 冒泡排序
* 插入排序
* 归并排序
* 堆排序
* 希尔排序
* 选择排序
* 计数排序
* 桶排序
* 基数排序
* ...

答题环节到了, sort 函数使用的以上哪一种算法?

如果你在网上搜索过关于 sort 源码的文章,可能会告诉你数组长度小于10用插入排序,否则用快速排序。

开始我也是这么认为的,可当我带着答案去 GitHub 验证的时候发现并非如此。

首先我并没有找到对应的 js 源码(文章说实现逻辑是用js写的),因为但新版本的V8源码已经修改,改用`V8 Torque`。`V8 Torque`是专门用来开发V8而创造的语言,语法类似TypeScript(再一次证明TypeScript的价值),它的编译器使用`CodeStubAssembler`转换成高效的汇编代码。
简单理解起来就是创造了一个类似TypeScript的高效的高级语言,这个语言的文件后缀是`tq`。

这里需要感谢 [justjavac](https://justjavac.com/about.html) 大神指点~

其次当我开始阅读源码的时候,并没有找到使用快速排序的代码,也没有找到判断数组长度的常数值10。

所有的证据表明,之前的源码解读文章很可能已经过时。

那么最新版本的 V8 用的是什么排序算法呢?

# 算法解读

V8引擎在xx版本之后就舍弃了快速排序,因为它不是稳定的排序算法,在最坏情况下,时间复杂度会降级到O(n^2)。
而是采用了一种混合排序的算法:TimSort。
这种功能算法最初用于Python语言中,严格地说它t不属于以上10种排序算法中的任何一种,属于一种混合排序算法:
在数据量小的子数组中使用**插入排序**,然后再使用**归并排序**将有序的子数组进行合并排序,时间复杂度为 O(nlogn) 。

结合V8源码,具体实现步骤如下:

1. 判断数组长度,小于2直接返回,不排序。
2. 开始循环。
3. 找出一个有序子数组,我们称之为“run”,长度为 currentRunLength 。
4. 计算最小合并序列长度 minRunLength (这个值会根据数组长度动态变化,在32~64之间)。
5. 比较 currentRunLength 和 minRunLength ,如果 currentRunLength >= minRunLength ,否则采用插入排序补足数组长度至 minRunLength ,将 run 压入栈 pendingRuns 中。
6. 每次有新的 run 被压入 pendingRuns 时保证栈内任意3个连续的 run(run0, run1, run2)从下至上满足run0>run1+run2 && run1>run2 ,不满足的话进行调整直至满足。
7. 如果剩余子数组为0,结束循环。
8. 合并栈中所有 run,排序结束。

# 源码解读

## 源码路径

`/thrid_party/v8/builtins/array-sort.tq`

## 调用栈

```
1386 ArrayPrototypeSort
1403 ArrayTimSort
1369 ArrayTimSortImpl
1260 ComputeMinRunLength // 计算 minRunLength
// while循环
1262 CountAndMakeRun // 计算当前 run 的长度
1267 BinaryInsertionSort // 用插入排序补足 run 长度
1274 MergeCollapse // 放入 pendingRuns 并根据需要进行调整
// 循环结束
1281 MergeForceCollapse // 合并 pendingRuns 中所有 run
```

## 核心源码

tq语言虽然有些不一样,但如果有TypeScript基础的话阅读起来应该不成问题。
下面重点解读3个函数的源码:

```
// 在while循环之前调用,每次排序只调用一次,用来计算 minRunLength
macro ComputeMinRunLength(nArg: Smi): Smi {
let n: Smi = nArg;
let r: Smi = 0;

assert(n >= 0);
// 不断除以2,得到结果在 32~64 之间
while (n >= 64) {
r = r | (n & 1);
n = n >> 1;
}

const minRunLength: Smi = n + r;
assert(nArg (workArray.objects[low]);
const elementLowPred = UnsafeCast(workArray.objects[low - 1]);
// 调用比对函数来比对数据
let order = sortState.Compare(elementLow, elementLowPred);

const isDescending: bool = order (workArray.objects[idx]);
order = sortState.Compare(currentElement, previousElement);

if (isDescending) {
if (order >= 0) break;
} else {
if (order run[n+1]+run[n+2] 且 run[n+1]>run2[n+2]
transitioning macro MergeCollapse(context: Context, sortState: SortState) {
const pendingRuns: FixedArray = sortState.pendingRuns;

while (GetPendingRunsSize(sortState) > 1) {
let n: Smi = GetPendingRunsSize(sortState) - 2;

if (!RunInvariantEstablished(pendingRuns, n + 1) ||
!RunInvariantEstablished(pendingRuns, n)) {
if (GetPendingRunLength(pendingRuns, n - 1) 【深度】扒开V8引擎的源码,我找到了你们想要的前端算法(下次面试官再问算法,用它怼回去!)

原文地址:https://www.cnblogs.com/yalishizhude/p/11462621.html

时间: 2024-10-17 16:14:24

【深度】扒开V8引擎的源码,我找到了你们想要的前端算法(下次面试官再问算法,用它怼回去!)的相关文章

关于阅读框架源码后的一些敢想

记得之前做毕业设计的时候看过status1的源码当时感觉挺简单的,不就是写几个xml配置文件然后在利用反射实例化成对象在执行相应的方法吗?当时以为自己好牛啊!以至于在学校做组合项目的时候自己自以为是的写了一个数据层的封装给组员使用,记得当时对外暴露的方法就是sql跟参数,庆幸的是组合项目完成后那个封装既然没出一点问题. 当自己现在再回过头去看status的源码的时候,感觉自己有些看不懂了.这两年也看了不少开源框架的源码像tomcat,heritrix,lucene,openfire,tigase

artTemplate模板引擎的源码拜读

最初接触的模板引擎还是基于node的ejs,当时觉得很神奇原来还可以这么玩,后来随着学习的深入,使用过jade,doT等,当然还有一些比较火的诸如juicer.underscore还没有深入接触,直到今年上半年由于项目需要就想着要不试试腾讯的artTemplate,感觉牛逼也吹的挺响的.开始了解后,觉得它比我之前使用过的jade.doT都好用,调试神马的也方便很多,采用预编译的方式也让性能非常优越. 其实看了源码后简单的总结出来就是这么一句话:就是先获取html中对应的id下得innerHTML

只需一句话就能搞定NVelocity模板引擎,源码+解析+文档+资料+注释

好长时间不发技术方面的动态了,今天无聊就发篇关于NVelocity的技术文章吧,这门技术来源于java开源项目Velocity,比较好用,其他的我也不过多介绍了,没听过的在文章末尾会有介绍,下面我们就实战吧~ 咱们直接上最简单的方法,一句话搞定: DNTNvelocityHelper.NvelocityTemplate(context.Request.MapPath("~/NVelocity/templates/"), context, "Templater_index.dn

java 在线编辑模版 代码编辑器 兼容手机平板PC freemaker 静态引擎 网站源码

java 企业网站源码 前后台都有 静态模版引擎, 代码生成器大大提高开发效率 前台: 支持三套模版, 可以在后台切换 系统介绍: 1.网站后台采用主流的 SSM 框架 jsp JSTL,网站后台采用freemaker静态化模版引擎生成html 2.因为是生成的html,所以访问速度快,轻便,对服务器负担小 3.网站前端采用主流的响应式布局,同一页面同时支持PC.平板.手机(三合一)浏览器访问 4.springmvc +spring4.2.5+ mybaits3.3  SSM 普通java we

Nodejs事件引擎libuv源码剖析之:高效线程池(threadpool)的实现

声明:本文为原创博文,转载请注明出处. Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线程模型的变种,无论其怎么演化,其核心组件都包含了Reactor实例(提供事件注册.注销.通知功能).多路复用器(由操作系统提供,比如kqueue.select.epoll等).事件处理器(负责事件的处理)以及事件源(linux中这就是描述符)这四个组件.一般,会单独启动一个线程运行Reactor实例来

Mahout推荐系统引擎RecommenderEvaluator源码解析

在http://blog.csdn.net/jianjian1992/article/details/47304337里边有关于推荐系统的完整代码,其中有一个评价器RecommenderEvaluator用来评价推荐器的好坏. RecommenderEvaluator evalutor = new AverageAbsoluteDifferenceRecommenderEvaluator(); System.out.println("eval:"+ evalutor.evaluate(

图像处理之增强---图像增强算法四种,图示与源码,包括retinex(ssr、msr、msrcr)和一种混合算法

申明:本文非笔者原创,原文转载自:http://blog.csdn.net/onezeros/article/details/6342661 两组图像:左边较暗,右边较亮 第一行是原图像,他们下面是用四种算法处理的结果 依次为: 1.一种混合算法 2.msr,multi-scale retinex 3.msrcr,multi-scale retinex with color restoration 4.ssr,single scale retinex           源码,retinex算法

B/S MVC工作流引擎 OA 源码

本源码是一款集成工作流引擎的ASP.NET MVC快速开发平台,由从事六年以上OA及工作流开发与实施的团队设计开发,该工作流平台已应用于众多大型企事业单位.拥有全浏览器兼容的可视化流程设计器.表单设计器.基于角色的权限管理等先进设计理念,是您开发OA.CRM.HR等企事业各种应用管理系统的最佳基础平台. Razor视图引擎 功能介绍1.流程测试:请假申请.物资采购申请.自定义表单.新闻发布.2.流程处理:待办事项.已办事项.签名管理.意见管理.工作委托.3.流程管理:流程设计.表单设计.按钮管理

【原创】使用JS封装的一个小型游戏引擎及源码分享

1 /** 2 * @description: 引擎的设计与实现 3 * @user: xiugang 4 * @time: 2018/10/01 5 */ 6 7 /* 8 * V1.0: 引擎实现的基本模块思路 9 * 1.创建一个游戏引擎对象及精灵对象 10 * 2.将精灵对象添加到引擎中去,并实现播放动画效果以及需要用到的回调方法 11 * 3.启动引擎 12 * */ 13 14 /* 15 * V2.0: 实现游戏循环模块 16 * 1.如果游戏暂停了,就跳过以下各步骤,并在100毫