@@ -30,7 +30,6 @@ public sealed class V8ScriptEngine : ScriptEngine, IJavaScriptEngine
3030 #region data
3131
3232 private static readonly DocumentInfo initScriptInfo = new DocumentInfo ( MiscHelpers . FormatInvariant ( "{0} [internal]" , nameof ( V8ScriptEngine ) ) ) ;
33- [ ThreadStatic ] private static bool bypassTaskPromiseConversion ;
3433
3534 private readonly V8ScriptEngineFlags engineFlags ;
3635 private readonly V8ContextProxy proxy ;
@@ -288,23 +287,25 @@ function construct() {
288287 return value instanceof savedPromise;
289288 },
290289
291- completePromiseWithResult: function (task , resolve, reject) {
290+ completePromiseWithResult: function (getResult , resolve, reject) {
292291 try {
293- resolve(task.Result );
292+ resolve(getResult() );
294293 }
295294 catch (exception) {
296295 reject(exception);
297296 }
297+ return undefined;
298298 },
299299
300- completePromise: function (task , resolve, reject) {
300+ completePromise: function (wait , resolve, reject) {
301301 try {
302- task.Wait ();
302+ wait ();
303303 resolve();
304304 }
305305 catch (exception) {
306306 reject(exception);
307307 }
308+ return undefined;
308309 },
309310
310311 throwValue: function (value) {
@@ -1101,6 +1102,26 @@ private void OnContinuationTimer(Timer timer)
11011102 }
11021103 }
11031104
1105+ private object CreatePromise ( Action < object , object > executor )
1106+ {
1107+ VerifyNotDisposed ( ) ;
1108+ var v8Script = ( V8ScriptItem ) script ;
1109+ var v8Internal = ( V8ScriptItem ) v8Script . GetProperty ( "EngineInternal" ) ;
1110+ return V8ScriptItem . Wrap ( this , v8Internal . InvokeMethod ( false , "createPromise" , executor ) ) ;
1111+ }
1112+
1113+ private void CompletePromise < T > ( Task < T > task , object resolve , object reject )
1114+ {
1115+ Func < T > getResult = ( ) => task . Result ;
1116+ Script . EngineInternal . completePromiseWithResult ( getResult , resolve , reject ) ;
1117+ }
1118+
1119+ private void CompletePromise ( Task task , object resolve , object reject )
1120+ {
1121+ Action wait = task . Wait ;
1122+ Script . EngineInternal . completePromise ( wait , resolve , reject ) ;
1123+ }
1124+
11041125 #endregion
11051126
11061127 #region ScriptEngine overrides (public members)
@@ -1289,7 +1310,7 @@ internal override object MarshalToScript(object obj, HostItemFlags flags)
12891310 return obj ;
12901311 }
12911312
1292- if ( engineFlags . HasFlag ( V8ScriptEngineFlags . EnableTaskPromiseConversion ) && ! bypassTaskPromiseConversion )
1313+ if ( engineFlags . HasFlag ( V8ScriptEngineFlags . EnableTaskPromiseConversion ) )
12931314 {
12941315 // .NET Core async functions return Task subclass instances that trigger result wrapping
12951316
@@ -1303,17 +1324,11 @@ internal override object MarshalToScript(object obj, HostItemFlags flags)
13031324 {
13041325 if ( testObject . GetType ( ) . IsAssignableToGenericType ( typeof ( Task < > ) , out var typeArgs ) )
13051326 {
1306- using ( Scope . Create ( ( ) => MiscHelpers . Exchange ( ref bypassTaskPromiseConversion , true ) , oldValue => bypassTaskPromiseConversion = oldValue ) )
1307- {
1308- obj = typeof ( TaskConverter < > ) . MakeSpecificType ( typeArgs ) . InvokeMember ( "ToPromise" , BindingFlags . InvokeMethod | BindingFlags . Public | BindingFlags . Static , null , null , new [ ] { testObject , this } ) ;
1309- }
1327+ obj = typeof ( TaskConverter < > ) . MakeSpecificType ( typeArgs ) . InvokeMember ( "ToPromise" , BindingFlags . InvokeMethod | BindingFlags . Public | BindingFlags . Static , null , null , new [ ] { testObject , this } ) ;
13101328 }
13111329 else if ( testObject is Task task )
13121330 {
1313- using ( Scope . Create ( ( ) => MiscHelpers . Exchange ( ref bypassTaskPromiseConversion , true ) , oldValue => bypassTaskPromiseConversion = oldValue ) )
1314- {
1315- obj = task . ToPromise ( this ) ;
1316- }
1331+ obj = task . ToPromise ( this ) ;
13171332 }
13181333 }
13191334 }
@@ -1378,12 +1393,9 @@ internal override object MarshalToHost(object obj, bool preserveHostTarget)
13781393 }
13791394
13801395 var scriptItem = V8ScriptItem . Wrap ( this , obj ) ;
1381- if ( engineFlags . HasFlag ( V8ScriptEngineFlags . EnableTaskPromiseConversion ) && ! bypassTaskPromiseConversion && ( obj is IV8Object v8Object ) && v8Object . IsPromise ( ) )
1396+ if ( engineFlags . HasFlag ( V8ScriptEngineFlags . EnableTaskPromiseConversion ) && ( obj is IV8Object v8Object ) && v8Object . IsPromise ( ) )
13821397 {
1383- using ( Scope . Create ( ( ) => MiscHelpers . Exchange ( ref bypassTaskPromiseConversion , true ) , oldValue => bypassTaskPromiseConversion = oldValue ) )
1384- {
1385- return scriptItem . ToTask ( ) ;
1386- }
1398+ return scriptItem . ToTask ( ) ;
13871399 }
13881400
13891401 return scriptItem ;
@@ -1505,20 +1517,51 @@ protected override void Dispose(bool disposing)
15051517
15061518 uint IJavaScriptEngine . BaseLanguageVersion => 8 ;
15071519
1508- void IJavaScriptEngine . CompletePromiseWithResult < T > ( Task < T > task , object resolve , object reject )
1520+ object IJavaScriptEngine . CreatePromiseForTask < T > ( Task < T > task )
15091521 {
1510- using ( Scope . Create ( ( ) => MiscHelpers . Exchange ( ref bypassTaskPromiseConversion , true ) , oldValue => bypassTaskPromiseConversion = oldValue ) )
1522+ return CreatePromise ( ( resolve , reject ) =>
15111523 {
1512- Script . EngineInternal . completePromiseWithResult ( task , resolve , reject ) ;
1513- }
1524+ task . ContinueWith ( _ => CompletePromise ( task , resolve , reject ) , TaskContinuationOptions . ExecuteSynchronously ) ;
1525+ } ) ;
15141526 }
15151527
1516- void IJavaScriptEngine . CompletePromise ( Task task , object resolve , object reject )
1528+ object IJavaScriptEngine . CreatePromiseForTask ( Task task )
15171529 {
1518- using ( Scope . Create ( ( ) => MiscHelpers . Exchange ( ref bypassTaskPromiseConversion , true ) , oldValue => bypassTaskPromiseConversion = oldValue ) )
1530+ return CreatePromise ( ( resolve , reject ) =>
15191531 {
1520- Script . EngineInternal . completePromise ( task , resolve , reject ) ;
1532+ task . ContinueWith ( _ => CompletePromise ( task , resolve , reject ) , TaskContinuationOptions . ExecuteSynchronously ) ;
1533+ } ) ;
1534+ }
1535+
1536+ Task < object > IJavaScriptEngine . CreateTaskForPromise ( ScriptObject promise )
1537+ {
1538+ if ( ! ( promise is V8ScriptItem v8Promise ) || ! v8Promise . IsPromise ( ) )
1539+ {
1540+ throw new ArgumentException ( "The object is not a V8 promise" , nameof ( promise ) ) ;
15211541 }
1542+
1543+ var source = new TaskCompletionSource < object > ( ) ;
1544+
1545+ Action < object > onResolved = result =>
1546+ {
1547+ source . SetResult ( result ) ;
1548+ } ;
1549+
1550+ Action < object > onRejected = error =>
1551+ {
1552+ try
1553+ {
1554+ Script . EngineInternal . throwValue ( error ) ;
1555+ }
1556+ catch ( Exception exception )
1557+ {
1558+ source . SetException ( exception ) ;
1559+ }
1560+ } ;
1561+
1562+ v8Promise . InvokeMethod ( false , "then" , onResolved , onRejected ) ;
1563+
1564+ return source . Task ;
15221565 }
15231566
15241567 #endregion
0 commit comments