Created
August 18, 2018 03:21
-
-
Save alexshen/d0c3d1b2669cfca5511cc1c640910060 to your computer and use it in GitHub Desktop.
A simple promise implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
public delegate void ProducerDelegate<T>(Action<T> resolve, Action<Exception> reject); | |
public class Promise<T> | |
{ | |
private T m_result; | |
private Exception m_error; | |
private bool m_fufilled; | |
private readonly List<Action<T>> m_resolveHandlers = new List<Action<T>>(); | |
private readonly List<Action<Exception>> m_rejectHandlers = new List<Action<Exception>>(); | |
public Promise(ProducerDelegate<T> producer) | |
{ | |
if (producer == null) | |
{ | |
throw new ArgumentNullException(nameof(producer)); | |
} | |
try | |
{ | |
producer(OnResolved, OnRejected); | |
} | |
catch (Exception e) | |
{ | |
OnRejected(e); | |
} | |
} | |
private Promise() { } | |
public static Promise<T> Reject(Exception e) | |
{ | |
var promise = new Promise<T>(); | |
promise.OnRejected(e); | |
return promise; | |
} | |
public static Promise<T> Resolve(T result) | |
{ | |
var promise = new Promise<T>(); | |
promise.OnResolved(result); | |
return promise; | |
} | |
void OnResolved(T result) | |
{ | |
if (m_fufilled) { return; } | |
m_fufilled = true; | |
m_result = result; | |
foreach (var resolve in m_resolveHandlers) | |
{ | |
resolve(m_result); | |
} | |
} | |
void OnRejected(Exception ex) | |
{ | |
if (m_fufilled) { return; } | |
m_fufilled = true; | |
m_error = ex; | |
foreach (var reject in m_rejectHandlers) | |
{ | |
reject(m_error); | |
} | |
} | |
public Promise<U> Then<U>(Func<T, Promise<U>> sinkProducer) | |
{ | |
if (sinkProducer == null) | |
{ | |
throw new ArgumentNullException(nameof(sinkProducer)); | |
} | |
if (m_fufilled) | |
{ | |
if (m_error == null) | |
{ | |
try | |
{ | |
return sinkProducer(m_result) ?? Promise<U>.Resolve(default(U)); | |
} | |
catch (Exception ex) | |
{ | |
return Promise<U>.Reject(ex); | |
} | |
} | |
else | |
{ | |
return Promise<U>.Reject(m_error); | |
} | |
} | |
else | |
{ | |
var proxy = new Promise<U>(); | |
m_resolveHandlers.Add(res => { | |
try | |
{ | |
var realPromise = sinkProducer(res) ?? Promise<U>.Resolve(default(U)); | |
realPromise | |
.Then<object>(realRes => { | |
proxy.OnResolved(realRes); | |
return null; | |
}); | |
} | |
catch (Exception ex) | |
{ | |
proxy.OnRejected(ex); | |
} | |
}); | |
m_rejectHandlers.Add(proxy.OnRejected); | |
return proxy; | |
} | |
} | |
public Promise<object> Catch(Action<Exception> onRejected) | |
{ | |
if (onRejected == null) | |
{ | |
throw new ArgumentNullException(nameof(onRejected)); | |
} | |
if (m_fufilled) | |
{ | |
if (m_error != null) | |
{ | |
try | |
{ | |
onRejected(m_error); | |
} | |
catch (Exception ex) | |
{ | |
return Promise<object>.Reject(ex); | |
} | |
} | |
return Promise<object>.Resolve(null); | |
} | |
else | |
{ | |
var proxy = new Promise<object>(); | |
m_resolveHandlers.Add(delegate | |
{ | |
proxy.OnResolved(null); | |
}); | |
m_rejectHandlers.Add(error => { | |
try | |
{ | |
onRejected(error); | |
proxy.OnResolved(null); | |
} | |
catch (Exception ex) | |
{ | |
proxy.OnRejected(ex); | |
} | |
}); | |
return proxy; | |
} | |
} | |
public Promise<T> Finally(Action onFinally) | |
{ | |
if (onFinally == null) | |
{ | |
throw new ArgumentNullException(nameof(onFinally)); | |
} | |
if (m_fufilled) | |
{ | |
try | |
{ | |
onFinally(); | |
return m_error == null ? Promise<T>.Resolve(m_result) : Promise<T>.Reject(m_error); | |
} | |
catch (Exception ex) | |
{ | |
return Promise<T>.Reject(ex); | |
} | |
} | |
else | |
{ | |
var proxy = new Promise<T>(); | |
m_resolveHandlers.Add(res => { | |
try | |
{ | |
onFinally(); | |
proxy.OnResolved(res); | |
} | |
catch (Exception ex) | |
{ | |
proxy.OnRejected(ex); | |
} | |
}); | |
m_rejectHandlers.Add(error => { | |
try | |
{ | |
onFinally(); | |
proxy.OnRejected(error); | |
} | |
catch (Exception ex) | |
{ | |
proxy.OnRejected(ex); | |
} | |
}); | |
return proxy; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment