/// <summary> /// Creates a new Promise instance from a task. /// </summary> /// <param name="task"> A task to wait on. </param> /// <returns> The Promise instance. </returns> /// <remarks> /// If the task is of type Task<object> then the result of the task will be used to /// resolve the promise. Otherwise, the promise is resolved with "undefined" as the value. /// </remarks> public PromiseInstance FromTask(Task task) { if (task == null) { throw new ArgumentNullException(nameof(task)); } // Create a new promise. var promise = new PromiseInstance(this.InstancePrototype); // Execute some code after the task completes. task.ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().OnCompleted(() => { // Enqueue an event which resolves the promise. Engine.EnqueueEvent(() => { try { if (task is Task <object> objectTask) { promise.Resolve(objectTask.Result); } else { promise.Resolve(Undefined.Value); } } catch (AggregateException ex) { if (ex.InnerExceptions.Count == 1) { var innerException = ex.InnerExceptions[0]; if (innerException is JavaScriptException innerJSException) { promise.Reject(innerJSException.GetErrorObject(Engine)); } else { promise.Reject(innerException.Message); } } else { promise.Reject(ex.Message); } } catch (JavaScriptException ex) { promise.Reject(ex.GetErrorObject(Engine)); } catch (Exception ex) { promise.Reject(ex.Message); } }); }); return(promise); }
/// <summary> /// Creates a new Promise instance. /// </summary> /// <param name="notify">A <see cref="INotifyCompletion"/> that will signal the success or failure of the promise.</param> /// <returns>The Promise instance.</returns> public PromiseInstance Construct <T>(T notify) where T : INotifyCompletion { var promise = new PromiseInstance(this.InstancePrototype); if (notify == null) { return(promise); } notify.OnCompleted(() => { try { promise.Resolve(TaskAwaiterCache.GetResult(notify)); } catch (JavaScriptException jex) { promise.Reject(jex.ErrorObject); } catch (Exception e) { promise.Reject(e.Message); } }); return(promise); }
public PromiseInstance Resolve(object result) { var promise = new PromiseInstance(this.InstancePrototype); promise.Resolve(result); return(promise); }
public PromiseInstance Resolve(object value) { // If the constructor of value === this, then return as is. if (value is PromiseInstance promise) { return(promise); } var result = new PromiseInstance(this.InstancePrototype); result.Resolve(value); return(result); }
public PromiseInstance Race(ObjectInstance iterable) { if (iterable == null) { throw new JavaScriptException(iterable.Engine, ErrorType.TypeError, "The parameter must be an iterable."); } var iterator = TypeUtilities.GetIterator(iterable.Engine, iterable); var promises = TypeUtilities.Iterate(iterator.Engine, iterator); var promise = new PromiseInstance(iterable.Engine.Promise.InstancePrototype); foreach (var promiseOrValue in promises) { if (promise.State != PromiseState.Pending) { break; } promise.Resolve(promiseOrValue); } return(promise); }
public PromiseInstance All(ObjectInstance iterable) { if (iterable == null) { throw new JavaScriptException(iterable.Engine, ErrorType.TypeError, "The parameter must be an iterable."); } var iterator = TypeUtilities.GetIterator(iterable.Engine, iterable); var promises = TypeUtilities.Iterate(iterator.Engine, iterator).ToList(); var results = Engine.Array.Construct(new object[promises.Count]); var count = promises.Count; var promise = new PromiseInstance(iterable.Engine.Promise.InstancePrototype); // The promise is resolved immediately if the iterable is empty. if (promises.Count == 0) { promise.Resolve(results); return(promise); } for (var i = 0; i < promises.Count; i++) { if (promise.State != PromiseState.Pending) { break; } if (promises[i] is PromiseInstance p) { if (p.State == PromiseState.Rejected) { promise.Reject(p.Result); break; } else if (p.State == PromiseState.Fulfilled) { results[i] = p.Result; if (--count == 0) { promise.Resolve(results); break; } continue; } var j = i; // Some C# versions need this. p.Then(new ClrStubFunction(Engine.FunctionInstancePrototype, "", 1, (engine, thisObj, args) => { if (promise.State != PromiseState.Pending) { return(Undefined.Value); } results[j] = args[0]; if (--count == 0) { promise.Resolve(results); } return(Undefined.Value); }), new ClrStubFunction(Engine.FunctionInstancePrototype, "", 1, (engine, thisObj, args) => { promise.Reject(args[0]); return(Undefined.Value); })); continue; } else if (promises[i] is ObjectInstance obj && obj.HasProperty("then")) { FunctionInstance then; try { then = obj.GetPropertyValue("then") as FunctionInstance; } catch (JavaScriptException jex) { promise.Reject(jex.ErrorObject); break; } if (then != null) { try { var j = i; // Some C# versions need this. var resolve = new ClrStubFunction(iterable.Engine.Function.InstancePrototype, (engine, ths, arg) => { if (promise.State != PromiseState.Pending) { return(Undefined.Value); } results[j] = arg.Length == 0 ? Undefined.Value : arg[0]; if (--count == 0) { promise.Resolve(results); } return(Undefined.Value); }); then.Call(obj, resolve, promise.RejectFunction); continue; } catch (JavaScriptException jex) { promise.Reject(jex.ErrorObject); break; } } } results[i] = promises[i]; if (--count == 0) { promise.Resolve(results); break; } } return(promise); }