Skip to content

Commit e6d18f8

Browse files
committed
🪳 Fixed a bug where a Promise might never resolve when calling Resolve or Reject immediately within an asynchronous method of JavaScriptNativeObject.
1 parent b25bd15 commit e6d18f8

5 files changed

Lines changed: 66 additions & 11 deletions

File tree

‎src/WinFormium/JavaScript/JavaScriptEngine.Render.cs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ private void OnJsResolveOrRejectRemotePromise(ProcessMessage args)
9797
using (CefObjectTracker.StartTracking())
9898
using (context.EnterOrFail())
9999
{
100-
var promise = promiseData.Promise;
100+
using var promise = promiseData.Promise;
101101

102102
if (message.Resolve)
103103
{
@@ -117,7 +117,7 @@ private void OnJsResolveOrRejectRemotePromise(ProcessMessage args)
117117
promise.RejectPromise(message.Data ?? string.Empty);
118118
}
119119

120-
promise.Dispose();
120+
//promise.Dispose();
121121
}
122122
}));
123123
}

‎src/WinFormium/JavaScript/JavaScriptEngine.cs‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,6 @@ private ProcessResponse OnJSCallNativeObjectMethod(ProcessRequest request)
253253
};
254254
}
255255

256-
257256
if (args.Asynconous)
258257
{
259258
var promise = args.Promise;
@@ -264,9 +263,6 @@ private ProcessResponse OnJSCallNativeObjectMethod(ProcessRequest request)
264263
return new ProcessResponse { Success = false, ExceptionMessage = "[WinFormium] CallNativeObjectMethod returned promise but it is null." };
265264
}
266265

267-
args.ReturnValue = $"{promise.GenerateCallId()}";
268-
269-
270266
promise.CallRemoteResovle += (json) =>
271267
{
272268
frame.SendProcessMessage(CefProcessId.Renderer, new JsResolveOrRejectRemotePromise
@@ -286,6 +282,11 @@ private ProcessResponse OnJSCallNativeObjectMethod(ProcessRequest request)
286282
Data = reason
287283
}.ToCefProcessMessage());
288284
};
285+
286+
args.ReturnValue = $"{promise.GenerateCallId()}";
287+
288+
promise.IsPromiseContextReady = true;
289+
289290
}
290291

291292

‎src/WinFormium/JavaScript/JavaScriptNativeObject.cs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// This file is part of the WinFormium project.
1+
// This file is part of the WinFormium project.
22
// Copyright (c) 2025 Xuanchen Lin all rights reserved.
33
// This project is licensed under the LGPL License.
44
// See the LICENSE file in the project root for more information.
@@ -162,6 +162,7 @@ public override void OnFunctionApply(NativeProxyObjectFunctionApplyEventArgs arg
162162
else if (_asyncFunctions.TryGetValue(args.PropertyName, out var asyncFunc))
163163
{
164164
var promise = args.ReturnPromise();
165+
165166
asyncFunc(args.ArgumentsAsJson, promise);
166167
}
167168
}

‎src/WinFormium/JavaScript/JavaScriptPromiseContext.cs‎

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// This file is part of the WinFormium project.
1+
// This file is part of the WinFormium project.
22
// Copyright (c) 2025 Xuanchen Lin all rights reserved.
33
// This project is licensed under the LGPL License.
44
// See the LICENSE file in the project root for more information.
@@ -15,6 +15,37 @@ public class JavaScriptPromiseContext
1515
/// </summary>
1616
private string? _remoteCallId = null;
1717

18+
internal bool IsPromiseContextReady
19+
{
20+
get;
21+
set
22+
{
23+
field = value;
24+
25+
if (_resolvesShouldBeCalledWhenContextReady is not null)
26+
{
27+
28+
_resolvesShouldBeCalledWhenContextReady.Invoke();
29+
}
30+
else if(_rejectsShouldBeCalledWhenContextReady is not null)
31+
{
32+
_rejectsShouldBeCalledWhenContextReady.Invoke();
33+
}
34+
}
35+
}
36+
37+
/// <summary>
38+
/// Gets or sets the action to invoke when the promise is resolved, if the context is not yet ready.
39+
/// </summary>
40+
private Action? _resolvesShouldBeCalledWhenContextReady;
41+
42+
/// <summary>
43+
/// Gets or sets the action to invoke when the promise is rejected, if the context is not yet ready.
44+
/// </summary>
45+
private Action? _rejectsShouldBeCalledWhenContextReady;
46+
47+
48+
1849
/// <summary>
1950
/// Generates and returns a unique call identifier for the remote promise invocation.
2051
/// </summary>
@@ -52,13 +83,25 @@ internal JavaScriptPromiseContext(int objectId)
5283
ObjectId = objectId;
5384
}
5485

86+
87+
5588
/// <summary>
5689
/// Resolves the promise with an optional return value in JSON format.
5790
/// </summary>
5891
/// <param name="returnValueAsJson">The return value as a JSON string, or <c>null</c> if not applicable.</param>
5992
public void Resolve(string? returnValueAsJson = null)
6093
{
61-
CallRemoteResovle?.Invoke(returnValueAsJson);
94+
if(IsPromiseContextReady)
95+
{
96+
CallRemoteResovle?.Invoke(returnValueAsJson);
97+
}
98+
else
99+
{
100+
_resolvesShouldBeCalledWhenContextReady = () =>
101+
{
102+
CallRemoteResovle?.Invoke(returnValueAsJson);
103+
};
104+
}
62105
}
63106

64107
/// <summary>
@@ -67,7 +110,17 @@ public void Resolve(string? returnValueAsJson = null)
67110
/// <param name="reason">The reason for rejection, or <c>null</c> if not specified.</param>
68111
public void Reject(string? reason = null)
69112
{
70-
CallRemoteReject?.Invoke(reason);
113+
if(IsPromiseContextReady)
114+
{
115+
CallRemoteReject?.Invoke(reason);
116+
}
117+
else
118+
{
119+
_rejectsShouldBeCalledWhenContextReady = () =>
120+
{
121+
CallRemoteReject?.Invoke(reason);
122+
};
123+
}
71124
}
72125

73126
/// <summary>

‎src/WinFormium/WinFormium.csproj‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
</PropertyGroup>
3030

3131
<PropertyGroup Condition="'$(Configuration)'=='Release'">
32-
<Version>1.2.109.7</Version>
32+
<Version>1.2.109.8</Version>
3333
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
3434
<GenerateDocumentationFile>True</GenerateDocumentationFile>
3535
<IncludeSymbols>true</IncludeSymbols>

0 commit comments

Comments
 (0)