Understanding Object.keys Order and V8 Property Handling to Fix a wxml2canvas Bug
This article explains why a WeChat mini‑program’s share card lost its QR code due to incorrect assumptions about Object.keys ordering, dives into the ECMAScript specification and V8’s internal property storage, and shows how to modify wxml2canvas to correctly sort elements and avoid the bug.
One day after a release a senior developer reported that the QR code at the bottom of a generated share card was missing, while the same card worked on other devices. The project uses the wxml2canvas library, which is outdated and the root cause of the bug.
The article walks through the debugging process, shows how Object.keys() ordering is defined in the ECMAScript spec, and explains why integer keys are sorted numerically while non‑integer keys keep their creation order.
TL;DR
The bug occurs because wxml2canvas assumes Object.keys() returns keys in creation order, but when keys are positive integers they are sorted ascending, causing the drawing order to be wrong.
How the bug is produced.
How to fix the bug.
What order Object.keys() returns.
How V8 handles object properties.
To reproduce the bug, the library builds a sorted object where each key is a node’s top value. Because integer keys are sorted, the drawing sequence becomes incorrect.
const sorted = {};
sorted[300] = {};
sorted[200] = {};
sorted[100] = {};
console.log(Object.keys(sorted)); // ['100','200','300']When a floating‑point key is added, the order changes:
const sorted = {};
sorted[300] = {};
sorted[100] = {};
sorted[200] = {};
sorted[50.5] = {};
console.log(Object.keys(sorted)); // ['100','200','300','50.5']The fix is to force all keys to be floating‑point numbers before sorting:
Object.keys(sorted).sort((a,b)=>a-b).forEach((top, topIndex)=>{
// do something
});According to the ECMAScript spec, Object.keys() ultimately uses the internal method [[OwnPropertyKeys]] , which returns keys in three phases: array‑index keys sorted numerically, then string keys in creation order, then Symbol keys in creation order.
Therefore, only valid array indices (positive integers) are sorted; negative numbers and floating‑point numbers are treated as strings and keep their insertion order.
V8 improves property access by separating properties into "elements" (array‑index keys) and "properties" (string keys). Elements are stored in a linear structure called "fast properties". Regular properties are also stored linearly but may be moved to a dictionary ("slow properties") when the object becomes large or undergoes many additions/deletions.
V8 also creates hidden classes to describe an object’s shape; objects with identical shapes share the same hidden class. When properties are added or removed, a new hidden class is generated.
To force V8 to use fast properties, developers can use helper functions such as toFastProperties (shown in the article) or the to-fast-properties npm package.
References:
wxml2canvas repository
ECMAScript spec for OwnPropertyKeys
Fast properties in V8
Various MDN and blog articles cited in the original text.
END – If you enjoyed the article, please share, like, and star the author’s profile for more updates.
IT Xianyu
We share common IT technologies (Java, Web, SQL, etc.) and practical applications of emerging software development techniques. New articles are posted daily. Follow IT Xianyu to stay ahead in tech. The IT Xianyu series is being regularly updated.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.