script: Improve dirty propagation and fix script-layout synchronization.

This fixes race conditions whereby layout and script could be running
simultaneously.

r? @jdm 
cc @cgaebel 
This doesn't take care of ancestors.

Shouldn't this just run `node.dirty` on each node, traversed preorder? All the dirtying code exits early, so it should be asymptotically the same, and not that much slower.