[fix] UIManager measurements don't block

A large number of layout measurements (and their corresponding tasks)
can block the main thread. Make the work async and try to keep the UI
responsive to user input while the layout work is taking place.
This commit is contained in:
Nicolas Gallagher
2018-05-23 11:04:47 -07:00
parent a82cfbe504
commit b4e3427fea
2 changed files with 29 additions and 25 deletions
+11 -7
View File
@@ -27,11 +27,13 @@ const getRect = node => {
const measureLayout = (node, relativeToNativeNode, callback) => { const measureLayout = (node, relativeToNativeNode, callback) => {
const relativeNode = relativeToNativeNode || (node && node.parentNode); const relativeNode = relativeToNativeNode || (node && node.parentNode);
if (node && relativeNode) { if (node && relativeNode) {
const relativeRect = getRect(relativeNode); setTimeout(() => {
const { height, left, top, width } = getRect(node); const relativeRect = getRect(relativeNode);
const x = left - relativeRect.left; const { height, left, top, width } = getRect(node);
const y = top - relativeRect.top; const x = left - relativeRect.left;
callback(x, y, width, height, left, top); const y = top - relativeRect.top;
callback(x, y, width, height, left, top);
}, 0);
} }
}; };
@@ -54,8 +56,10 @@ const UIManager = {
measureInWindow(node, callback) { measureInWindow(node, callback) {
if (node) { if (node) {
const { height, left, top, width } = getRect(node); setTimeout(() => {
callback(left, top, width, height); const { height, left, top, width } = getRect(node);
callback(left, top, width, height);
}, 0);
} }
}, },
+18 -18
View File
@@ -56,9 +56,7 @@ const observe = instance => {
resizeObserver.observe(node); resizeObserver.observe(node);
} else { } else {
instance._layoutId = id; instance._layoutId = id;
setTimeout(() => { instance._handleLayout();
instance._handleLayout();
}, 0);
} }
}; };
@@ -122,22 +120,24 @@ const applyLayout = Component => {
const layout = this._layoutState; const layout = this._layoutState;
const { onLayout } = this.props; const { onLayout } = this.props;
if (this._isMounted && onLayout) { if (onLayout) {
this.measure((x, y, width, height) => { this.measure((x, y, width, height) => {
if ( if (this._isMounted) {
layout.x !== x || if (
layout.y !== y || layout.x !== x ||
layout.width !== width || layout.y !== y ||
layout.height !== height layout.width !== width ||
) { layout.height !== height
this._layoutState = { x, y, width, height }; ) {
const nativeEvent = { this._layoutState = { x, y, width, height };
layout: this._layoutState, const nativeEvent = {
get target() { layout: this._layoutState,
return findNodeHandle(this); get target() {
} return findNodeHandle(this);
}; }
onLayout({ nativeEvent, timeStamp: Date.now() }); };
onLayout({ nativeEvent, timeStamp: Date.now() });
}
} }
}); });
} }