@@ -28,7 +28,7 @@ module Miso.Internal
28
28
) where
29
29
-----------------------------------------------------------------------------
30
30
import Control.Exception (throwIO )
31
- import Control.Concurrent (ThreadId , killThread , threadDelay )
31
+ import Control.Concurrent (ThreadId , killThread )
32
32
import Control.Monad (forM , forM_ , when , void )
33
33
import Control.Monad.IO.Class
34
34
import qualified Data.Aeson as A
@@ -37,6 +37,7 @@ import Data.IORef (IORef, newIORef, atomicModifyIORef', readIORef, ato
37
37
import Data.Map.Strict (Map )
38
38
import qualified Data.Map.Strict as M
39
39
import qualified Data.Sequence as S
40
+ import Data.Sequence (Seq )
40
41
import qualified JavaScript.Array as JSArray
41
42
import Language.Javascript.JSaddle
42
43
import Prelude hiding (null )
@@ -89,7 +90,7 @@ initialize App {..} getView = do
89
90
atomicWriteIORef componentModel newModel
90
91
syncPoint
91
92
eventLoop newModel
92
- componentMainThread <- FFI. forkJSM (eventLoop model)
93
+ _ <- FFI. forkJSM (eventLoop model)
93
94
registerComponent ComponentState {.. }
94
95
delegator componentMount componentVTree events (logLevel `elem` [DebugEvents , DebugAll ])
95
96
forM_ initialAction componentSink
@@ -106,12 +107,12 @@ data Prerender
106
107
data ComponentState model action
107
108
= ComponentState
108
109
{ componentName :: MisoString
109
- , componentMainThread :: ThreadId
110
110
, componentSubThreads :: [ThreadId ]
111
111
, componentMount :: JSVal
112
112
, componentVTree :: IORef VTree
113
113
, componentSink :: action -> JSM ()
114
114
, componentModel :: IORef model
115
+ , componentActions :: IORef (Seq action )
115
116
}
116
117
-----------------------------------------------------------------------------
117
118
-- | componentMap
@@ -205,19 +206,33 @@ drawComponent prerender name App {..} snk = do
205
206
ref <- liftIO (newIORef vtree)
206
207
pure (name, mountElement, ref)
207
208
-----------------------------------------------------------------------------
209
+ -- | Drains the event queue before unmounting, executed synchronously
210
+ drain
211
+ :: App effect model action a
212
+ -> ComponentState model action
213
+ -> JSM ()
214
+ drain app@ App {.. } cs@ ComponentState {.. } = do
215
+ actions <- liftIO $ atomicModifyIORef' componentActions $ \ actions -> (S. empty, actions)
216
+ if S. null actions then pure () else go actions
217
+ where
218
+ go as = do
219
+ x <- liftIO (readIORef componentModel)
220
+ y <- foldEffects translate update componentSink (toList as) x
221
+ liftIO (atomicWriteIORef componentModel y)
222
+ drain app cs
223
+ -----------------------------------------------------------------------------
208
224
-- | Helper function for cleanly destroying a @Component@
209
225
unmount
210
226
:: Function
211
227
-> App effect model action a
212
228
-> ComponentState model action
213
229
-> JSM ()
214
- unmount mountCallback App {.. } ComponentState {.. } = do
230
+ unmount mountCallback app @ App {.. } cs @ ComponentState {.. } = do
215
231
undelegator componentMount componentVTree events (logLevel `elem` [DebugEvents , DebugAll ])
216
232
freeFunction mountCallback
217
233
liftIO (mapM_ killThread componentSubThreads)
218
- liftIO $ do
219
- killThread componentMainThread
220
- modifyIORef' componentMap (M. delete componentName)
234
+ drain app cs
235
+ liftIO $ modifyIORef' componentMap (M. delete componentName)
221
236
-----------------------------------------------------------------------------
222
237
-- | Internal function for construction of a Virtual DOM.
223
238
--
@@ -243,9 +258,7 @@ runView prerender (Embed attributes (SomeComponent (Component key mount app))) s
243
258
FFI. syncCallback $ do
244
259
M. lookup mount <$> liftIO (readIORef componentMap) >>= \ case
245
260
Nothing -> pure ()
246
- Just componentState -> do
247
- liftIO (threadDelay (millis 1 ))
248
- -- dmj ^ introduce 1ms delay to account for recursive component unmounting
261
+ Just componentState ->
249
262
unmount mountCallback app componentState
250
263
vcomp <- createNode " vcomp" HTML key " div"
251
264
setAttrs vcomp attributes snk (logLevel app) (events app)
@@ -352,10 +365,6 @@ registerComponent componentState = liftIO
352
365
$ modifyIORef' componentMap
353
366
$ M. insert (componentName componentState) componentState
354
367
-----------------------------------------------------------------------------
355
- -- | Millisecond helper, converts microseconds to milliseconds
356
- millis :: Int -> Int
357
- millis = (* 1000 )
358
- -----------------------------------------------------------------------------
359
368
-- | Registers components in the global state
360
369
renderStyles :: [CSS ] -> JSM ()
361
370
renderStyles styles =
0 commit comments