Skip to content

Commit 85f7e60

Browse files
committed
Implement basic error tolerance
1 parent 561b13c commit 85f7e60

File tree

1 file changed

+27
-5
lines changed

1 file changed

+27
-5
lines changed

render/render.js

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,24 @@ module.exports = function($window) {
1010
math: "http://www.w3.org/1998/Math/MathML"
1111
}
1212

13+
var hookError, hookThrown
1314
var onevent
1415
function setEventCallback(callback) {return onevent = callback}
1516

1617
function getNameSpace(vnode) {
1718
return vnode.attrs && vnode.attrs.xmlns || nameSpace[vnode.tag]
1819
}
1920

21+
function fail(message) {
22+
hookThrown = true
23+
hookError = new Error(message)
24+
}
25+
2026
//sanity check to discourage people from doing `vnode.state = ...`
2127
function checkState(vnode, original) {
22-
if (vnode.state !== original) throw new Error("`vnode.state` must not be modified")
28+
if (vnode.state !== original) {
29+
fail("`vnode.state` must not be modified")
30+
}
2331
}
2432

2533
//Note: the hook is passed as the `this` argument to allow proxying the
@@ -30,6 +38,9 @@ module.exports = function($window) {
3038
var original = vnode.state
3139
try {
3240
return this.apply(original, arguments)
41+
} catch (e) {
42+
hookThrown = true
43+
hookError = e
3344
} finally {
3445
checkState(vnode, original)
3546
}
@@ -155,7 +166,7 @@ module.exports = function($window) {
155166
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
156167
initLifecycle(vnode.state, vnode, hooks)
157168
vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode))
158-
if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument")
169+
if (vnode.instance === vnode) fail("A view cannot return the vnode it received as argument")
159170
sentinel.$$reentrantLock$$ = null
160171
}
161172
function createComponent(parent, vnode, hooks, ns, nextSibling) {
@@ -510,7 +521,7 @@ module.exports = function($window) {
510521
}
511522
function updateComponent(parent, old, vnode, hooks, nextSibling, ns) {
512523
vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode))
513-
if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument")
524+
if (vnode.instance === vnode) fail("A view cannot return the vnode it received as argument")
514525
if (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks)
515526
updateLifecycle(vnode.state, vnode, hooks)
516527
if (vnode.instance != null) {
@@ -619,7 +630,7 @@ module.exports = function($window) {
619630
var content = children[0].children
620631
if (vnode.dom.innerHTML !== content) vnode.dom.innerHTML = content
621632
}
622-
else if (vnode.text != null || children != null && children.length !== 0) throw new Error("Child node of a contenteditable must be trusted")
633+
else if (vnode.text != null || children != null && children.length !== 0) fail("Child node of a contenteditable must be trusted")
623634
}
624635

625636
//remove
@@ -852,19 +863,22 @@ module.exports = function($window) {
852863
if (typeof source.onupdate === "function") hooks.push(callHook.bind(source.onupdate, vnode))
853864
}
854865
function shouldNotUpdate(vnode, old) {
866+
var prevHookThrown = hookThrown
855867
var forceVnodeUpdate, forceComponentUpdate
868+
hookThrown = false
856869
if (vnode.attrs != null && typeof vnode.attrs.onbeforeupdate === "function") {
857870
forceVnodeUpdate = callHook.call(vnode.attrs.onbeforeupdate, vnode, old)
858871
}
859872
if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeupdate === "function") {
860873
forceComponentUpdate = callHook.call(vnode.state.onbeforeupdate, vnode, old)
861874
}
862-
if (!(forceVnodeUpdate === undefined && forceComponentUpdate === undefined) && !forceVnodeUpdate && !forceComponentUpdate) {
875+
if (hookThrown || !(forceVnodeUpdate === undefined && forceComponentUpdate === undefined) && !forceVnodeUpdate && !forceComponentUpdate) {
863876
vnode.dom = old.dom
864877
vnode.domSize = old.domSize
865878
vnode.instance = old.instance
866879
return true
867880
}
881+
hookThrown = prevHookThrown
868882
return false
869883
}
870884

@@ -878,11 +892,19 @@ module.exports = function($window) {
878892
if (dom.vnodes == null) dom.textContent = ""
879893

880894
vnodes = Vnode.normalizeChildren(Array.isArray(vnodes) ? vnodes : [vnodes])
895+
var prevHookError = hookError
896+
var prevHookThrown = hookThrown
897+
hookThrown = false
881898
updateNodes(dom, dom.vnodes, vnodes, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace)
882899
dom.vnodes = vnodes
883900
// document.activeElement can return null in IE https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
884901
if (active != null && activeElement() !== active && typeof active.focus === "function") active.focus()
885902
for (var i = 0; i < hooks.length; i++) hooks[i]()
903+
var nextHookThrown = hookThrown
904+
var nextHookError = hookError
905+
hookThrown = prevHookThrown
906+
hookError = prevHookError
907+
if (nextHookThrown) throw nextHookError
886908
}
887909

888910
return {render: render, setEventCallback: setEventCallback}

0 commit comments

Comments
 (0)