Skip to content

Commit f2ea242

Browse files
committed
Fixes for Promise
1 parent 49b0037 commit f2ea242

File tree

4 files changed

+82
-37
lines changed

4 files changed

+82
-37
lines changed

NiL.JS/BaseLibrary/Array.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@ private static long iterateImpl(JSValue self, JSValue callbackFn, JSValue thisBi
748748
if (method.GetCustomAttribute(typeof(InstanceMemberAttribute)) != null)
749749
fullMethodName += "prototype.";
750750
fullMethodName += method.Name;
751-
ExceptionHelper.Throw(new TypeError("Can not call " + fullMethodName + " for null or undefined"));
751+
ExceptionHelper.Throw(new TypeError("Cannot call " + fullMethodName + " for null or undefined"));
752752
#endif
753753
}
754754

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

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

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

22882288
return notExists;
22892289
}

NiL.JS/BaseLibrary/Promise.cs

Lines changed: 71 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using System.Collections;
3-
using System.Collections.Generic;
43
using System.Linq;
4+
using System.Runtime.ExceptionServices;
55
using System.Threading;
66
using System.Threading.Tasks;
77
using NiL.JS.Core;
@@ -81,11 +81,11 @@ internal Promise(Task<JSValue> task)
8181
{
8282
if (t.Status == TaskStatus.RanToCompletion)
8383
{
84-
handlePromiseCascade(t.Result);
84+
handlePromiseCascade(t.Result, false);
8585
}
8686
else if (t.Status == TaskStatus.Faulted)
8787
{
88-
_outerTask.SetException(t.Exception);
88+
_outerTask.SetException(t.Exception.GetBaseException() ?? t.Exception);
8989
}
9090
else
9191
{
@@ -109,19 +109,28 @@ internal Promise(Task<JSValue> task)
109109
_innerTask = task.ContinueWith(continuation);
110110
}
111111

112-
private void handlePromiseCascade(JSValue value)
112+
private void handlePromiseCascade(JSValue value, bool error)
113113
{
114114
var task = (value?.Value as Promise)?.Task ?? value?.Value as Task<JSValue>;
115115
if (task != null)
116116
{
117117
task.ContinueWith((t) =>
118118
{
119-
handlePromiseCascade(t.Result);
119+
if (t.IsFaulted)
120+
{
121+
var exception = t.Exception.GetBaseException() as JSException ?? t.Exception.GetBaseException() ?? t.Exception;
122+
_outerTask.SetException(exception);
123+
}
124+
else
125+
handlePromiseCascade(t.Result, false);
120126
});
121127
}
122128
else
123129
{
124-
_outerTask.SetResult(value);
130+
if (error)
131+
_outerTask.SetException(new JSException(value));
132+
else
133+
_outerTask.SetResult(value);
125134
}
126135
}
127136

@@ -139,7 +148,7 @@ private void callbackInvoke()
139148
{
140149
statusSet = true;
141150

142-
handlePromiseCascade(args[0]);
151+
handlePromiseCascade(args[0], false);
143152
}
144153

145154
return null;
@@ -151,7 +160,7 @@ private void callbackInvoke()
151160
{
152161
statusSet = true;
153162

154-
handlePromiseCascade(args[0]);
163+
handlePromiseCascade(args[0], true);
155164
}
156165

157166
return null;
@@ -173,13 +182,20 @@ private void callbackInvoke()
173182
throw;
174183
}
175184

176-
if (!statusSet)
177-
_outerTask.SetResult(JSValue.undefined);
185+
//if (!statusSet)
186+
// _outerTask.SetResult(JSValue.undefined);
178187
}
179188

180189
public static Promise resolve(JSValue data)
181190
{
182-
return new Promise(fromResult(data));
191+
return data.As<Promise>() ?? new Promise(fromResult(data));
192+
}
193+
194+
public static Promise reject(JSValue data)
195+
{
196+
var result = new Promise();
197+
result._outerTask.SetException(new JSException(data));
198+
return result;
183199
}
184200

185201
public static Promise race(IIterable promises)
@@ -212,36 +228,50 @@ public Promise then(Function onFulfilment, Function onRejection)
212228
{
213229
return then(
214230
onFulfilment == null ? null : value => onFulfilment.Call(JSValue.undefined, new Arguments { value }),
215-
onRejection == null ? null : value => onRejection.Call(JSValue.undefined, new Arguments { value }));
231+
onRejection == null ? null : value => onRejection.Call(JSValue.undefined, new Arguments { value }),
232+
false);
233+
}
234+
235+
public Promise @finally(Function onFinally)
236+
{
237+
Func<JSValue, JSValue> func = onFinally == null ? null : value => onFinally.Call(JSValue.undefined, new Arguments { value });
238+
return then(func, func, true);
216239
}
217240

218241
[Hidden]
219-
public Promise then(Func<JSValue, JSValue> onFulfilment, Func<JSValue, JSValue> onRejection)
242+
public Promise then(Func<JSValue, JSValue> onFulfilment, Func<JSValue, JSValue> onRejection, bool rethrow)
220243
{
221244
if (onFulfilment == null && onRejection == null)
222245
return resolve(JSValue.undefined);
223246

224-
var thenTask = onFulfilment == null ? null : _outerTask.Task.ContinueWith(task => onFulfilment(Result), TaskContinuationOptions.OnlyOnRanToCompletion);
225-
226-
var catchTask = onRejection == null ? null :
227-
_outerTask.Task.ContinueWith(task =>
247+
var catchTask = onRejection == null
248+
? null
249+
: _outerTask.Task.ContinueWith(task =>
228250
{
229-
Exception ex = task.Exception;
230-
while (ex.InnerException != null)
231-
ex = ex.InnerException;
232-
233-
var jsException = ex as JSException;
234-
if (jsException != null)
251+
Exception ex = task.Exception.GetBaseException();
252+
JSValue result;
253+
if (ex is JSException jsException)
235254
{
236-
return onRejection(jsException.Error);
255+
result = onRejection(jsException.Error);
237256
}
238257
else
239258
{
240-
return onRejection(Context.CurrentGlobalContext.ProxyValue(task.Exception.GetBaseException()));
259+
result = onRejection(Context.CurrentGlobalContext.ProxyValue(ex));
241260
}
261+
262+
if (rethrow)
263+
ExceptionDispatchInfo.Capture(ex).Throw();
264+
265+
return result;
242266
},
243267
TaskContinuationOptions.NotOnRanToCompletion);
244268

269+
var thenTask = onFulfilment == null
270+
? null
271+
: catchTask is not null
272+
? _outerTask.Task.ContinueWith(task => onFulfilment(task.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
273+
: _outerTask.Task.ContinueWith(task => onFulfilment(task.Result));
274+
245275
if (thenTask != null)
246276
{
247277
if (catchTask != null)
@@ -308,14 +338,24 @@ private static Task<JSValue[]> whenAll(Task<JSValue>[] tasks)
308338

309339
Action<Task<JSValue>> contination = t =>
310340
{
311-
var index = System.Array.IndexOf(tasks, t);
312-
if (t.IsCanceled)
313-
throw new OperationCanceledException();
341+
if (task.Task.IsCompleted)
342+
return;
314343

315-
result[index] = t.Result;
344+
try
345+
{
346+
var index = System.Array.IndexOf(tasks, t);
347+
if (t.IsCanceled)
348+
throw new OperationCanceledException();
349+
350+
result[index] = t.Result;
316351

317-
if (Interlocked.Decrement(ref count) == 0)
318-
task.SetResult(result);
352+
if (Interlocked.Decrement(ref count) == 0)
353+
task.SetResult(result);
354+
}
355+
catch (Exception e)
356+
{
357+
task.SetException(e.GetBaseException() ?? e);
358+
}
319359
};
320360

321361
for (var i = 0; i < tasks.Length; i++)

NiL.JS/Core/Functions/AsyncFunction.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ private JSValue subscribeOrReturnValue(JSValue promiseOrValue)
3535

3636
if (promiseOrValue.Value is Promise promise)
3737
{
38-
var result = promise.then(then, fail);
38+
var result = promise.then(then, fail, false);
3939
return _context.GlobalContext.ProxyValue(result);
4040
}
4141
else

NiL.JS/Core/JSException.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,14 @@ private JSException()
2727
}
2828

2929
public JSException(Error data)
30+
: this(Context.CurrentGlobalContext.ProxyValue(data))
31+
{
32+
}
33+
34+
public JSException(JSValue data)
3035
: this()
3136
{
32-
Error = Context.CurrentGlobalContext.ProxyValue(data);
37+
Error = data;
3338
}
3439

3540
public JSException(Error data, CodeNode exceptionMaker)

0 commit comments

Comments
 (0)