Skip to content

Commit

Permalink
UnwrapIfPromise Call RunAvailableContinuations (#1813)
Browse files Browse the repository at this point in the history
  • Loading branch information
scgm0 authored Apr 5, 2024
1 parent 00d6a6e commit b6f99b9
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 10 deletions.
50 changes: 50 additions & 0 deletions Jint.Tests/Runtime/AsyncTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -228,4 +228,54 @@ async function foo(name) {

Assert.Equal(expected, log.Select(x => x.AsString()).ToArray());
}

[Fact]
public void ShouldPromiseBeResolved()
{
var log = new List<string>();
Engine engine = new();
engine.SetValue("log", (string str) =>
{
log.Add(str);
});

const string Script = """
async function main() {
return new Promise(function (resolve) {
log('Promise!')
resolve(null)
}).then(function () {
log('Resolved!')
});
}
""";
var result = engine.Execute(Script);
var val = result.GetValue("main");
val.Call().UnwrapIfPromise();
Assert.Equal(2, log.Count);
Assert.Equal("Promise!", log[0]);
Assert.Equal("Resolved!", log[1]);
}

[Fact]
public void ShouldPromiseBeResolved2()
{
Engine engine = new();
engine.SetValue("setTimeout",
(Action action, int ms) =>
{
Task.Delay(ms).ContinueWith(_ => action());
});

const string Script = """
var delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function main() {
await delay(100);
return 1;
}
""";
var result = engine.Execute(Script);
var val = result.GetValue("main").Call();
Assert.Equal(1, val.UnwrapIfPromise().AsInteger());
}
}
12 changes: 12 additions & 0 deletions Jint/JsValueExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,18 @@ public static JsValue UnwrapIfPromise(this JsValue value)
{
if (value is JsPromise promise)
{
var engine = promise.Engine;
var task = promise.TaskCompletionSource.Task;
engine.RunAvailableContinuations();
engine.AddToEventLoop(() =>
{
if (!task.IsCompleted)
{
// Task.Wait has the potential of inlining the task's execution on the current thread; avoid this.
((IAsyncResult) task).AsyncWaitHandle.WaitOne();
}
});
engine.RunAvailableContinuations();
switch (promise.State)
{
case PromiseState.Pending:
Expand Down
2 changes: 2 additions & 0 deletions Jint/Native/Date/MimeKit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,9 @@ private static bool TryParseStandardDateFormat(List<DateToken> tokens, byte[] te
return true;
}

#pragma warning disable CA1859
private static bool TryParseUnknownDateFormat(IList<DateToken> tokens, byte[] text, out DateTimeOffset date)
#pragma warning restore CA1859
{
int? day = null, month = null, year = null, tzone = null;
int hour = 0, minute = 0, second = 0;
Expand Down
3 changes: 3 additions & 0 deletions Jint/Native/JsPromise.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ internal sealed class JsPromise : ObjectInstance

// valid only in settled state (Fulfilled or Rejected)
internal JsValue Value { get; private set; } = null!;
internal TaskCompletionSource<JsPromise> TaskCompletionSource { get; }= new();

internal List<PromiseReaction> PromiseRejectReactions = new();
internal List<PromiseReaction> PromiseFulfillReactions = new();
Expand Down Expand Up @@ -126,6 +127,7 @@ private JsValue RejectPromise(JsValue reason)
var reactions = PromiseRejectReactions;
PromiseRejectReactions = new List<PromiseReaction>();
PromiseFulfillReactions.Clear();
TaskCompletionSource.SetCanceled();

// Note that this part is skipped because there is no tracking yet
// 7. If promise.[[PromiseIsHandled]] is false, perform HostPromiseRejectionTracker(promise, "reject").
Expand All @@ -145,6 +147,7 @@ private JsValue FulfillPromise(JsValue result)
var reactions = PromiseFulfillReactions;
PromiseFulfillReactions = new List<PromiseReaction>();
PromiseRejectReactions.Clear();
TaskCompletionSource.SetResult(this);

return PromiseOperations.TriggerPromiseReactions(_engine, reactions, result);
}
Expand Down
9 changes: 0 additions & 9 deletions Jint/Native/JsValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,6 @@ internal static JsValue ConvertTaskToPromise(Engine engine, Task task)
}
});

engine.AddToEventLoop(() =>
{
if (!task.IsCompleted)
{
// Task.Wait has the potential of inlining the task's execution on the current thread; avoid this.
((IAsyncResult) task).AsyncWaitHandle.WaitOne();
}
});

return promise;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ protected override object EvaluateInternal(EvaluationContext context)
value = promiseInstance;
}

engine.RunAvailableContinuations();
return value.UnwrapIfPromise();
}
catch (PromiseRejectedException e)
Expand Down

0 comments on commit b6f99b9

Please sign in to comment.