Skip to content

Commit 694f3b3

Browse files
authored
Workaround for promise continuations (#89)
1 parent 31f9350 commit 694f3b3

File tree

4 files changed

+62
-23
lines changed

4 files changed

+62
-23
lines changed

Modules/@babylonjs/react-native/EngineHook.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,6 @@ export function useEngine(): Engine | undefined {
7575
}
7676
})();
7777

78-
// NOTE: This is a workaround for https://github.com/BabylonJS/BabylonReactNative/issues/60
79-
function heartbeat() {
80-
if (!disposed) {
81-
setTimeout(heartbeat, 10);
82-
}
83-
}
84-
heartbeat();
85-
8678
return () => {
8779
disposed = true;
8880
setEngine(engine => {

Modules/@babylonjs/react-native/android/src/main/cpp/BabylonNativeInterop.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
#include <jsi/jsi.h>
2424

25+
#include "../../../../shared/Shared.h"
26+
2527
namespace Babylon
2628
{
2729
namespace
@@ -39,14 +41,29 @@ namespace Babylon
3941
Native(facebook::jsi::Runtime* jsiRuntime, ANativeWindow* windowPtr)
4042
: m_env{ Napi::Attach<facebook::jsi::Runtime&>(*jsiRuntime) }
4143
{
42-
auto looper_scheduler = std::make_shared<looper_scheduler_t>(looper_scheduler_t::get_for_current_thread());
44+
struct DispatchData
45+
{
46+
using looper_scheduler_t = arcana::looper_scheduler<128>;
47+
48+
looper_scheduler_t scheduler;
49+
Napi::FunctionReference flushedQueue;
4350

44-
JsRuntime::DispatchFunctionT dispatchFunction{[env = m_env, looper_scheduler = std::move(looper_scheduler)](std::function<void(Napi::Env)> func) {
45-
(*looper_scheduler)([env, func = std::move(func)]()
51+
DispatchData(Napi::Env env)
52+
: scheduler{ looper_scheduler_t::get_for_current_thread() }
53+
, flushedQueue{ GetFlushedQueue(env) }
4654
{
47-
func(env);
48-
});
49-
}};
55+
}
56+
};
57+
58+
JsRuntime::DispatchFunctionT dispatchFunction =
59+
[env = m_env, data = std::make_shared<DispatchData>(m_env)](std::function<void(Napi::Env)> func)
60+
{
61+
(data->scheduler)([env, func = std::move(func), &data]()
62+
{
63+
func(env);
64+
data->flushedQueue.Call({});
65+
});
66+
};
5067

5168
m_runtime = &JsRuntime::CreateForJavaScript(m_env, dispatchFunction);
5269

@@ -100,8 +117,6 @@ namespace Babylon
100117
}
101118

102119
private:
103-
using looper_scheduler_t = arcana::looper_scheduler<sizeof(std::weak_ptr<Napi::Env>) + sizeof(std::function<void(Napi::Env)>)>;
104-
105120
std::unique_ptr<Graphics> m_graphics{};
106121
Napi::Env m_env;
107122
JsRuntime* m_runtime;

Modules/@babylonjs/react-native/ios/BabylonNative.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include <sstream>
1919
#include <unistd.h>
2020

21+
#include "../shared/Shared.h"
22+
2123
namespace Babylon
2224
{
2325
using namespace facebook;
@@ -43,15 +45,27 @@ namespace Babylon
4345
m_impl->m_graphics = Graphics::InitializeFromWindow<void*>(windowPtr, width, height);
4446
});
4547

46-
auto run_loop_scheduler = std::make_shared<arcana::run_loop_scheduler>(arcana::run_loop_scheduler::get_for_current_thread());
47-
48-
JsRuntime::DispatchFunctionT dispatchFunction{[env = m_impl->env, run_loop_scheduler = std::move(run_loop_scheduler)](std::function<void(Napi::Env)> func)
48+
struct DispatchData
4949
{
50-
(*run_loop_scheduler)([env, func = std::move(func)]()
50+
arcana::run_loop_scheduler scheduler;
51+
Napi::FunctionReference flushedQueue;
52+
53+
DispatchData(Napi::Env env)
54+
: scheduler{ arcana::run_loop_scheduler::get_for_current_thread() }
55+
, flushedQueue{ GetFlushedQueue(env) }
56+
{
57+
}
58+
};
59+
60+
JsRuntime::DispatchFunctionT dispatchFunction =
61+
[env = m_impl->env, data = std::make_shared<DispatchData>(m_impl->env)](std::function<void(Napi::Env)> func)
5162
{
52-
func(env);
53-
});
54-
}};
63+
(data->scheduler)([env, func = std::move(func), &data]()
64+
{
65+
func(env);
66+
data->flushedQueue.Call({});
67+
});
68+
};
5569

5670
m_impl->runtime = &JsRuntime::CreateForJavaScript(m_impl->env, std::move(dispatchFunction));
5771

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#pragma once
2+
3+
#include <napi/napi.h>
4+
5+
// See https://github.com/BabylonJS/BabylonReactNative/issues/60 for original issue.
6+
// This is a work around to poke the React Native message queue to run setImmediate callbacks.
7+
// React Native uses a custom promise implementation based on setImmediate. The promise
8+
// continuations will only continue once these setImmediate callbacks are triggered by the
9+
// flushedQueue call. This is explicitly called at the end of JsRuntime's dispatch function
10+
// to flush the queue.
11+
inline Napi::FunctionReference GetFlushedQueue(Napi::Env env)
12+
{
13+
// HACK: The __fbBatchedBridge global is an internal implementation of React Native.
14+
// This hack will break if React Native internals changes, but it should blow up right here.
15+
auto batchedBridge{ env.Global().Get("__fbBatchedBridge").As<Napi::Object>() };
16+
auto flushedQueue{ batchedBridge.Get("flushedQueue").As<Napi::Function>() };
17+
return Napi::Persistent(flushedQueue);
18+
}

0 commit comments

Comments
 (0)