JavaScript 数组遍历动态增长问题(V8源码解析)
2021/5/10 22:25:12
本文主要是介绍JavaScript 数组遍历动态增长问题(V8源码解析),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
数组 arr 在遍历同时动态增长会发生什么呢
let arr = [1,2] arr.forEach(item => arr.push(...arr)) console.log(arr) // 输出: [ 1, 2, 1, 2, 1, 2, 1, 2 ]
并未输出 [1,2] 或 [1,2,1,2...] 无限循环下去
JavaScript引擎:V8源码git地址:https://github.com/v8/v8
vscode打开源码文件夹
V8-MASTER/src/builtins-collections-gen.cc
数组遍历的循环由 Goto 与 BIND 搭配完成,Goto(adress) 指跳转的目标adress , BIND(adress) 指对应接受的目的地adress
- 记录数组初始信息:所以遍历时
Label loop(this, {&var_index, &var_table}), done_loop(this);
var_index
:已遍历的长度var_table
:可遍历的容量(长度)done_loop
循环完成时的地址- 在遍历时
push
并未改变var_table
指向的值
Goto(&loop)
跳到BIND(&loop)
Goto(&done_loop)
跳到BIND(&done_loop)
callback_not_callable
函数不可调用的话也会跳出去
TF_BUILTIN(MapPrototypeForEach, CollectionsBuiltinsAssembler) { const char* const kMethodName = "Map.prototype.forEach"; // Array 继承自 MapCollections ...... // Ensure that {callback} is actually callable. Label callback_not_callable(this, Label::kDeferred); GotoIf(TaggedIsSmi(callback), &callback_not_callable); GotoIfNot(IsCallable(CAST(callback)), &callback_not_callable); TVARIABLE(IntPtrT, var_index, IntPtrConstant(0)); TVARIABLE(OrderedHashMap, var_table, CAST(LoadObjectField(CAST(receiver), JSMap::kTableOffset))); Label loop(this, {&var_index, &var_table}), done_loop(this); // 记录了数组的初始信息,后期判断是否遍历结束的标志 Goto(&loop); BIND(&loop); { // 中括号内的依然会执行,只是产生了一个块作用域 // 代码快内部执行完后,会被回收资源 // Transition {table} and {index} if there was any modification to // the {receiver} while we're iterating. TNode<IntPtrT> index = var_index.value(); TNode<OrderedHashMap> table = var_table.value(); std::tie(table, index) = Transition<OrderedHashMap>( table, index, [](const TNode<OrderedHashMap>, const TNode<IntPtrT>) {}); // Read the next entry from the {table}, skipping holes. TNode<Object> entry_key; TNode<IntPtrT> entry_start_position; std::tie(entry_key, entry_start_position, index) = NextSkipHoles<OrderedHashMap>(table, index, &done_loop); // Load the entry value as well. TNode<Object> entry_value = LoadFixedArrayElement( table, entry_start_position, (OrderedHashMap::HashTableStartIndex() + OrderedHashMap::kValueOffset) * kTaggedSize); // Invoke the {callback} passing the {entry_key}, {entry_value} and the // {receiver}. Call(context, callback, this_arg, entry_value, entry_key, receiver); // Continue with the next entry. var_index = index; var_table = table; Goto(&loop); } BIND(&done_loop); args.PopAndReturn(UndefinedConstant()); BIND(&callback_not_callable); ...... }
-
Goto(&loop)
进入 {中括号循环代码块,运行完后会清除资源} 循环 -
NextSkipHoles<OrderedHashMap>(table, index, &done_loop);
判断是否结束,传入了&done_loop
-
NextSkipHoles 函数找一下源码
GotoIfNot
根据比较条件判断是否Goto(if_end)
done_loop
的值传给了if_end
CollectionsBuiltinsAssembler::NextSkipHoles(TNode<TableType> table, TNode<IntPtrT> index, Label* if_end) { // 比较已使用的容量与总容量 // Compute the used capacity for the {table}. TNode<IntPtrT> number_of_buckets = LoadAndUntagObjectField(table, TableType::NumberOfBucketsOffset()); TNode<IntPtrT> number_of_elements = LoadAndUntagObjectField(table, TableType::NumberOfElementsOffset()); TNode<IntPtrT> number_of_deleted_elements = LoadAndUntagObjectField( table, TableType::NumberOfDeletedElementsOffset()); TNode<IntPtrT> used_capacity = IntPtrAdd(number_of_elements, number_of_deleted_elements); TNode<Object> entry_key; TNode<IntPtrT> entry_start_position; TVARIABLE(IntPtrT, var_index, index); Label loop(this, &var_index), done_loop(this); Goto(&loop); BIND(&loop); { GotoIfNot(IntPtrLessThan(var_index.value(), used_capacity), if_end); //判断是否跳出 entry_start_position = IntPtrAdd( IntPtrMul(var_index.value(), IntPtrConstant(TableType::kEntrySize)), number_of_buckets); entry_key = UnsafeLoadFixedArrayElement( table, entry_start_position, TableType::HashTableStartIndex() * kTaggedSize); Increment(&var_index); Branch(IsTheHole(entry_key), &loop, &done_loop); }
这篇关于JavaScript 数组遍历动态增长问题(V8源码解析)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-24Java中定时任务实现方式及源码剖析
- 2024-11-24Java中定时任务实现方式及源码剖析
- 2024-11-24鸿蒙原生开发手记:03-元服务开发全流程(开发元服务,只需要看这一篇文章)
- 2024-11-24细说敏捷:敏捷四会之每日站会
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解