-
-
Notifications
You must be signed in to change notification settings - Fork 39
Expand file tree
/
Copy pathPromiseProxy.cpp
More file actions
89 lines (80 loc) · 3.56 KB
/
PromiseProxy.cpp
File metadata and controls
89 lines (80 loc) · 3.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include "PromiseProxy.h"
#include "Helpers.h"
using namespace v8;
namespace tns {
void PromiseProxy::Init(v8::Local<v8::Context> context) {
std::string source = R"(
// Ensure that Promise callbacks are executed on the
// same thread on which they were created
(() => {
global.Promise = new Proxy(global.Promise, {
construct: function(target, args) {
let origFunc = args[0];
let runloop = CFRunLoopGetCurrent();
let promise = new target(function(resolve, reject) {
function isFulfilled() {
return !resolve;
}
function markFulfilled() {
origFunc = null;
resolve = null;
reject = null;
}
origFunc(value => {
if (isFulfilled()) {
return;
}
const resolveCall = resolve.bind(this, value);
if (runloop === CFRunLoopGetCurrent()) {
markFulfilled();
resolveCall();
} else {
CFRunLoopPerformBlock(runloop, kCFRunLoopDefaultMode, resolveCall);
CFRunLoopWakeUp(runloop);
markFulfilled();
}
}, reason => {
if (isFulfilled()) {
return;
}
const rejectCall = reject.bind(this, reason);
if (runloop === CFRunLoopGetCurrent()) {
markFulfilled();
rejectCall();
} else {
CFRunLoopPerformBlock(runloop, kCFRunLoopDefaultMode, rejectCall);
CFRunLoopWakeUp(runloop);
markFulfilled();
}
});
});
return new Proxy(promise, {
get: function(target, name) {
let orig = target[name];
if (name === "then" || name === "catch" || name === "finally") {
return orig.bind(target);
}
return typeof orig === 'function' ? function(x) {
if (runloop === CFRunLoopGetCurrent()) {
orig.bind(target, x)();
return target;
}
CFRunLoopPerformBlock(runloop, kCFRunLoopDefaultMode, orig.bind(target, x));
CFRunLoopWakeUp(runloop);
return target;
} : orig;
}
});
}
});
})();
)";
Isolate* isolate = context->GetIsolate();
Local<Script> script;
bool success = Script::Compile(context, tns::ToV8String(isolate, source)).ToLocal(&script);
tns::Assert(success && !script.IsEmpty(), isolate);
Local<Value> result;
success = script->Run(context).ToLocal(&result);
tns::Assert(success, isolate);
}
}