Skip to content

Instantly share code, notes, and snippets.

@alexshen
Created August 18, 2018 03:21
Show Gist options
  • Save alexshen/d0c3d1b2669cfca5511cc1c640910060 to your computer and use it in GitHub Desktop.
Save alexshen/d0c3d1b2669cfca5511cc1c640910060 to your computer and use it in GitHub Desktop.
A simple promise implementation
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