2
0
Эх сурвалжийг харах

UnwrapIfPromise Call RunAvailableContinuations (#1813)

神麤詭末 1 жил өмнө
parent
commit
b6f99b9455

+ 50 - 0
Jint.Tests/Runtime/AsyncTests.cs

@@ -228,4 +228,54 @@ public class AsyncTests
 
         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 - 0
Jint/JsValueExtensions.cs

@@ -630,6 +630,18 @@ public static class JsValueExtensions
     {
         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:

+ 2 - 0
Jint/Native/Date/MimeKit.cs

@@ -454,7 +454,9 @@ internal static class DateUtils
         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;

+ 3 - 0
Jint/Native/JsPromise.cs

@@ -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();
@@ -126,6 +127,7 @@ internal sealed class JsPromise : ObjectInstance
         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").
@@ -145,6 +147,7 @@ internal sealed class JsPromise : ObjectInstance
         var reactions = PromiseFulfillReactions;
         PromiseFulfillReactions = new List<PromiseReaction>();
         PromiseRejectReactions.Clear();
+        TaskCompletionSource.SetResult(this);
 
         return PromiseOperations.TriggerPromiseReactions(_engine, reactions, result);
     }

+ 0 - 9
Jint/Native/JsValue.cs

@@ -178,15 +178,6 @@ namespace Jint.Native
                 }
             });
 
-            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;
         }
 

+ 0 - 1
Jint/Runtime/Interpreter/Expressions/JintAwaitExpression.cs

@@ -34,7 +34,6 @@ internal sealed class JintAwaitExpression : JintExpression
                 value = promiseInstance;
             }
 
-            engine.RunAvailableContinuations();
             return value.UnwrapIfPromise();
         }
         catch (PromiseRejectedException e)