diff --git a/website/guide/performance.html b/website/guide/performance.html index 1200e80a..d3ba3e5c 100644 --- a/website/guide/performance.html +++ b/website/guide/performance.html @@ -144,6 +144,23 @@ slower.
them up from the global object or other objects +When an object is enumerated, with either the for-in
statement
+or Object.keys()
, Duktape first traverses the target object and its
+prototype chain and forms an internal enumeration object, which contains all
+the enumeration keys as strings.
+In particular, all array indices (or character indices in case of
+strings) are converted and interned into string values before enumeration and
+they remain interned until the enumeration completes. This can be memory
+intensive especially if large arrays or strings are enumerated.
Note, however, that iterating a string or an array with for-in
+and expecting the array elements or string indices to be enumerated in an
+ascending order is non-portable. Such behavior, while guaranteed by many
+implementations including Duktape, is not guaranteed by the Ecmascript
+standard.
Ecmascript has a lot of features which make function entry and execution @@ -273,6 +290,41 @@ for (var i = 0; i <= 1000; i++) { } +
Because the internal enumeration object contains all (used) array
+indices converted to string values, avoid for-in
enumeration
+of at least large arrays. As a concrete example, consider:
+var a = []; +for (var i = 0; i < 1000000; i++) { + a[i] = i; +} +for (var i in a) { + // Before this loop is first entered, a million strings ("0", "1", + // ..., "999999") will be interned. + print(i, a[i]); +} +// The million strings become garbage collectable only here. ++ +
The internal enumeration object created in this example would contain a +million interned string keys for "0", "1", ..., "999999". All of these keys +would remain reachable for the entire duration of the enumeration. The +following code would perform much better (and would be more portable, as it +makes no assumptions on enumeration order):
+ ++var a = []; +for (var i = 0; i < 1000000; i++) { + a[i] = i; +} +var n = a.length; +for (var i = 0; i < n; i++) { + print(i, a[i]); +} ++
Identifier accesses in global and eval code always use slow path instructions