Skip to content

Commit

Permalink
Fixes for Promise
Browse files Browse the repository at this point in the history
  • Loading branch information
nilproject committed Nov 5, 2023
1 parent 49b0037 commit f2ea242
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 37 deletions.
8 changes: 4 additions & 4 deletions NiL.JS/BaseLibrary/Array.cs
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ private static long iterateImpl(JSValue self, JSValue callbackFn, JSValue thisBi
if (method.GetCustomAttribute(typeof(InstanceMemberAttribute)) != null)
fullMethodName += "prototype.";
fullMethodName += method.Name;
ExceptionHelper.Throw(new TypeError("Can not call " + fullMethodName + " for null or undefined"));
ExceptionHelper.Throw(new TypeError("Cannot call " + fullMethodName + " for null or undefined"));
#endif
}

Expand Down Expand Up @@ -930,7 +930,7 @@ private static long reverseIterateImpl(JSValue self, Arguments args, JSValue sta
ExceptionHelper.Throw(new TypeError("Trying to call method for for null or undefined"));
#else
var stackTrace = new System.Diagnostics.StackTrace();
ExceptionHelper.Throw(new TypeError("Can not call Array.prototype." + stackTrace.GetFrame(stackTrace.FrameCount - 2).GetMethod().Name + " for null or undefined"));
ExceptionHelper.Throw(new TypeError("Cannot call Array.prototype." + stackTrace.GetFrame(stackTrace.FrameCount - 2).GetMethod().Name + " for null or undefined"));
#endif
}

Expand Down Expand Up @@ -1510,7 +1510,7 @@ public static JSValue slice(JSValue self, Arguments args)
if (args == null)
throw new ArgumentNullException("args");
if (!self.Defined || (self._valueType >= JSValueType.Object && self._oValue == null))
ExceptionHelper.Throw(new TypeError("Can not call Array.prototype.slice for null or undefined"));
ExceptionHelper.Throw(new TypeError("Cannot call Array.prototype.slice for null or undefined"));

var result = new Array();
var index = 0L;
Expand Down Expand Up @@ -2283,7 +2283,7 @@ internal protected override JSValue GetProperty(JSValue key, bool forWrite, Prop
if (_lengthObj != null && (_lengthObj._attributes & JSValueAttributesInternal.ReadOnly) != 0 && index >= _data.Length)
{
if (memberScope == PropertyScope.Own)
ExceptionHelper.Throw(new TypeError("Can not add item into fixed size array"));
ExceptionHelper.Throw(new TypeError("Cannot add item into fixed size array"));

return notExists;
}
Expand Down
102 changes: 71 additions & 31 deletions NiL.JS/BaseLibrary/Promise.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;
using NiL.JS.Core;
Expand Down Expand Up @@ -81,11 +81,11 @@ internal Promise(Task<JSValue> task)
{
if (t.Status == TaskStatus.RanToCompletion)
{
handlePromiseCascade(t.Result);
handlePromiseCascade(t.Result, false);
}
else if (t.Status == TaskStatus.Faulted)
{
_outerTask.SetException(t.Exception);
_outerTask.SetException(t.Exception.GetBaseException() ?? t.Exception);
}
else
{
Expand All @@ -109,19 +109,28 @@ internal Promise(Task<JSValue> task)
_innerTask = task.ContinueWith(continuation);
}

private void handlePromiseCascade(JSValue value)
private void handlePromiseCascade(JSValue value, bool error)
{
var task = (value?.Value as Promise)?.Task ?? value?.Value as Task<JSValue>;
if (task != null)
{
task.ContinueWith((t) =>
{
handlePromiseCascade(t.Result);
if (t.IsFaulted)
{
var exception = t.Exception.GetBaseException() as JSException ?? t.Exception.GetBaseException() ?? t.Exception;
_outerTask.SetException(exception);
}
else
handlePromiseCascade(t.Result, false);
});
}
else
{
_outerTask.SetResult(value);
if (error)
_outerTask.SetException(new JSException(value));
else
_outerTask.SetResult(value);
}
}

Expand All @@ -139,7 +148,7 @@ private void callbackInvoke()
{
statusSet = true;
handlePromiseCascade(args[0]);
handlePromiseCascade(args[0], false);
}
return null;
Expand All @@ -151,7 +160,7 @@ private void callbackInvoke()
{
statusSet = true;
handlePromiseCascade(args[0]);
handlePromiseCascade(args[0], true);
}
return null;
Expand All @@ -173,13 +182,20 @@ private void callbackInvoke()
throw;
}

if (!statusSet)
_outerTask.SetResult(JSValue.undefined);
//if (!statusSet)
// _outerTask.SetResult(JSValue.undefined);
}

public static Promise resolve(JSValue data)
{
return new Promise(fromResult(data));
return data.As<Promise>() ?? new Promise(fromResult(data));
}

public static Promise reject(JSValue data)
{
var result = new Promise();
result._outerTask.SetException(new JSException(data));
return result;
}

public static Promise race(IIterable promises)
Expand Down Expand Up @@ -212,36 +228,50 @@ public Promise then(Function onFulfilment, Function onRejection)
{
return then(
onFulfilment == null ? null : value => onFulfilment.Call(JSValue.undefined, new Arguments { value }),
onRejection == null ? null : value => onRejection.Call(JSValue.undefined, new Arguments { value }));
onRejection == null ? null : value => onRejection.Call(JSValue.undefined, new Arguments { value }),
false);
}

public Promise @finally(Function onFinally)
{
Func<JSValue, JSValue> func = onFinally == null ? null : value => onFinally.Call(JSValue.undefined, new Arguments { value });
return then(func, func, true);
}

[Hidden]
public Promise then(Func<JSValue, JSValue> onFulfilment, Func<JSValue, JSValue> onRejection)
public Promise then(Func<JSValue, JSValue> onFulfilment, Func<JSValue, JSValue> onRejection, bool rethrow)
{
if (onFulfilment == null && onRejection == null)
return resolve(JSValue.undefined);

var thenTask = onFulfilment == null ? null : _outerTask.Task.ContinueWith(task => onFulfilment(Result), TaskContinuationOptions.OnlyOnRanToCompletion);

var catchTask = onRejection == null ? null :
_outerTask.Task.ContinueWith(task =>
var catchTask = onRejection == null
? null
: _outerTask.Task.ContinueWith(task =>
{
Exception ex = task.Exception;
while (ex.InnerException != null)
ex = ex.InnerException;
var jsException = ex as JSException;
if (jsException != null)
Exception ex = task.Exception.GetBaseException();
JSValue result;
if (ex is JSException jsException)
{
return onRejection(jsException.Error);
result = onRejection(jsException.Error);
}
else
{
return onRejection(Context.CurrentGlobalContext.ProxyValue(task.Exception.GetBaseException()));
result = onRejection(Context.CurrentGlobalContext.ProxyValue(ex));
}
if (rethrow)
ExceptionDispatchInfo.Capture(ex).Throw();
return result;
},
TaskContinuationOptions.NotOnRanToCompletion);

var thenTask = onFulfilment == null
? null
: catchTask is not null
? _outerTask.Task.ContinueWith(task => onFulfilment(task.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
: _outerTask.Task.ContinueWith(task => onFulfilment(task.Result));

if (thenTask != null)
{
if (catchTask != null)
Expand Down Expand Up @@ -308,14 +338,24 @@ private static Task<JSValue[]> whenAll(Task<JSValue>[] tasks)

Action<Task<JSValue>> contination = t =>
{
var index = System.Array.IndexOf(tasks, t);
if (t.IsCanceled)
throw new OperationCanceledException();
if (task.Task.IsCompleted)
return;
result[index] = t.Result;
try
{
var index = System.Array.IndexOf(tasks, t);
if (t.IsCanceled)
throw new OperationCanceledException();
result[index] = t.Result;
if (Interlocked.Decrement(ref count) == 0)
task.SetResult(result);
if (Interlocked.Decrement(ref count) == 0)
task.SetResult(result);
}
catch (Exception e)
{
task.SetException(e.GetBaseException() ?? e);
}
};

for (var i = 0; i < tasks.Length; i++)
Expand Down
2 changes: 1 addition & 1 deletion NiL.JS/Core/Functions/AsyncFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ private JSValue subscribeOrReturnValue(JSValue promiseOrValue)

if (promiseOrValue.Value is Promise promise)
{
var result = promise.then(then, fail);
var result = promise.then(then, fail, false);
return _context.GlobalContext.ProxyValue(result);
}
else
Expand Down
7 changes: 6 additions & 1 deletion NiL.JS/Core/JSException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,14 @@ private JSException()
}

public JSException(Error data)
: this(Context.CurrentGlobalContext.ProxyValue(data))
{
}

public JSException(JSValue data)
: this()
{
Error = Context.CurrentGlobalContext.ProxyValue(data);
Error = data;
}

public JSException(Error data, CodeNode exceptionMaker)
Expand Down

0 comments on commit f2ea242

Please sign in to comment.