Skip to content

Commit b4a1cc2

Browse files
authored
Do typeof string check before looking for String constructor (#4198)
In `constructNewChildrenArray` we look for the `String` constructor to support #4151 (i.e. strings created with `new String`). However, doing this check first leads to a megamorphic deopt in `constructorNewChildrenArray` since V8 has many different internal types for strings, leading to a megamorphic access for `childVNode.constructor` in the common case (normal strings and VNodes). This PR adds back the `typeof childVNode == 'string'` check to catch normal strings first before falling back to `childVNode.constructor == String` to check for manually constructed strings. Commits: * Add back typeof string check in diffChildren (+5 B) * Store matching oldVNode in variable in constructNewChildrenArray (-4 B) * Inline insertion checks into skew block (-3 B)
1 parent f269b62 commit b4a1cc2

File tree

1 file changed

+18
-16
lines changed

1 file changed

+18
-16
lines changed

src/diff/children.js

+18-16
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,11 @@ function constructNewChildrenArray(newParentVNode, renderResult, oldChildren) {
191191
// or we are rendering a component (e.g. setState) copy the oldVNodes so it can have
192192
// it's own DOM & etc. pointers
193193
else if (
194-
childVNode.constructor == String ||
194+
typeof childVNode == 'string' ||
195195
typeof childVNode == 'number' ||
196196
// eslint-disable-next-line valid-typeof
197-
typeof childVNode == 'bigint'
197+
typeof childVNode == 'bigint' ||
198+
childVNode.constructor == String
198199
) {
199200
childVNode = newParentVNode._children[i] = createVNode(
200201
null,
@@ -269,25 +270,29 @@ function constructNewChildrenArray(newParentVNode, renderResult, oldChildren) {
269270
// final index after using this property to get the oldVNode
270271
childVNode._index = matchingIndex;
271272

273+
oldVNode = null;
272274
if (matchingIndex !== -1) {
275+
oldVNode = oldChildren[matchingIndex];
273276
remainingOldChildren--;
274-
if (oldChildren[matchingIndex]) {
275-
oldChildren[matchingIndex]._flags |= MATCHED;
277+
if (oldVNode) {
278+
oldVNode._flags |= MATCHED;
276279
}
277280
}
278281

279282
// Here, we define isMounting for the purposes of the skew diffing
280283
// algorithm. Nodes that are unsuspending are considered mounting and we detect
281284
// this by checking if oldVNode._original === null
282-
const isMounting =
283-
matchingIndex === -1 ||
284-
oldChildren[matchingIndex] == null ||
285-
oldChildren[matchingIndex]._original === null;
285+
const isMounting = oldVNode == null || oldVNode._original === null;
286286

287287
if (isMounting) {
288288
if (matchingIndex == -1) {
289289
skew--;
290290
}
291+
292+
// If we are mounting a DOM VNode, mark it for insertion
293+
if (typeof childVNode.type != 'function') {
294+
childVNode._flags |= INSERT_VNODE;
295+
}
291296
} else if (matchingIndex !== skewedIndex) {
292297
if (matchingIndex === skewedIndex + 1) {
293298
skew++;
@@ -307,15 +312,12 @@ function constructNewChildrenArray(newParentVNode, renderResult, oldChildren) {
307312
} else {
308313
skew = 0;
309314
}
310-
}
311315

312-
// Move this VNode's DOM if the original index (matchingIndex) doesn't match
313-
// the new skew index (i + new skew) or it's a mounting DOM VNode
314-
if (
315-
matchingIndex !== i + skew ||
316-
(typeof childVNode.type != 'function' && isMounting)
317-
) {
318-
childVNode._flags |= INSERT_VNODE;
316+
// Move this VNode's DOM if the original index (matchingIndex) doesn't
317+
// match the new skew index (i + new skew)
318+
if (matchingIndex !== i + skew) {
319+
childVNode._flags |= INSERT_VNODE;
320+
}
319321
}
320322
}
321323

0 commit comments

Comments
 (0)