-
-
Notifications
You must be signed in to change notification settings - Fork 926
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
render: wrap stateResult and attrsResult in Promise.resolve(), fix #2592 #3005
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Edit: misread the original issue.
I'd like to see the section of code cleaned up a bit, especially since it can now exploit the fact the callback's truly only ever called once. This would be better IMO for that section.
// This separation naturally ensures that the remove finalizer callback is only
// created if removal is actually blocked.
function tryBlockRemove(parent, vnode, source, counter) {
if (typeof source.onbeforeremove !== "function") return
var original = vnode.state
var result = callHook.call(vnode.state.onbeforeremove, vnode)
if (result == null) return
Promise.resolve(result).finally(() => {
checkState(vnode, original)
tryResumeRemove(parent, vnode, generation, counter)
})
counter.v++
generation = currentRender
for (var dom of domFor(vnode)) delayedRemoval.set(dom, generation)
}
function tryResumeRemove(parent, vnode, generation, counter) {
if (!--counter.v) {
onremove(vnode)
removeDOM(parent, vnode, generation)
}
}
function removeNode(parent, vnode) {
var counter = {v: 1}
if (typeof vnode.tag !== "string") tryBlockRemove(parent, vnode, vnode.state, counter)
if (vnode.attrs) tryBlockRemove(parent, vnode, vnode.attrs, counter)
tryResumeRemove(parent, vnode, generation, counter)
}
Separately, if you're feeling up for it (you very much don't have to), I'd be happy to see that var delayedRemoval = new WeakMap()
function eachDOM(vnode, fn, arg, generation) {
var dom = vnode.dom
var domSize = vnode.domSize
while (domSize) {
var nextSibling = dom.nextSibling
if (delayedRemoval.get(dom) !== generation) {
fn(dom, arg)
domSize--
}
dom = nextSibling
}
}
// ...
function appendChild(dom, target) {
target.appendChild(dom)
}
function moveDOM(parent, vnode, nextSibling) {
var target = vnode.dom
if (target != null) {
// don't allocate for the common case
if (vnode.domSize > 1) {
target = getDocument(parent).createDocumentFragment()
eachDOM(vnode, appendChild, target)
}
insertDOM(parent, target, nextSibling)
}
}
// ...
function markGeneration(dom) {
delayedRemoval.set(dom, generation)
}
// From my earlier change request
function tryBlockRemove(parent, vnode, source, counter) {
// ...
generation = currentRender
eachDOM(vnode, markGeneration)
}
// ...
function removeChild(dom, parent) {
parent.removeChild(dom)
}
function removeDOM(parent, vnode, generation) {
eachDOM(vnode, removeChild, parent, generation)
}
// ... This would also imply setting |
@dead-claudia Thanks for your review comments.
Also, I personally agree with moving the domFor helper to render, but do you mean to delete the public API m.domFor()? |
@kfule That function haa never been exported. It's an implementation detail. |
@dead-claudia It appears that the user can access the domFor helper as m.domFor(). Although I think the useful cases are very limited. Line 1748 in e57011c
|
@kfule I had no idea that was being exported. Worth noting this function has never been documented. There is a use case, though, and it normally looks like this: return m.fragment({
oncreate(vnode) {
const inputElems = m.domFor(vnode)
},
}, things.map(thing => m("input", {
// ...
})) So we could keep it around and just modify it so it can work correctly in In any case, keeping it as-is isn't a good idea. Our needs differ from what would be useful in the public API. |
@dead-claudia
What you wrote " |
Description
This PR wraps the return value of onbeforeremove in Promise.resolve(). This ensures that thenable objects are also always processed asynchronously.
Motivation and Context
fix #2592.
The current implementation of mithril calls finally() instead of then() in onbeforeremove process, so that returning a simple thenable object in onbeforeremove will throw an error.
How Has This Been Tested?
npm run test
including additional and modified tests.Types of changes
Checklist