Mercurial > pub > ImplabNet
annotate Implab/Promise.cs @ 106:d4e38929ce36 v2
promises refactoring
| author | cin | 
|---|---|
| date | Mon, 10 Nov 2014 18:00:28 +0300 | 
| parents | 4d308952fd5e | 
| children | f5220e5472ef | 
| rev | line source | 
|---|---|
| 2 | 1 using System; | 
| 2 using System.Collections.Generic; | |
| 3 using System.Reflection; | |
| 4 using System.Threading; | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 5 using Implab.Parallels; | 
| 2 | 6 | 
| 7 namespace Implab { | |
| 8 | |
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 9 /// <summary> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 10 /// Класс для асинхронного получения результатов. Так называемое "обещание". | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 11 /// </summary> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 12 /// <typeparam name="T">Тип получаемого результата</typeparam> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 13 /// <remarks> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 14 /// <para>Сервис при обращении к его методу дает обещаиние о выполнении операции, | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 15 /// клиент получив такое обещание может установить ряд обратных вызово для получения | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 16 /// событий выполнения обещания, тоесть завершения операции и предоставлении результатов.</para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 17 /// <para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 18 /// Обещение может быть как выполнено, так и выполнено с ошибкой. Для подписки на | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 19 /// данные события клиент должен использовать методы <c>Then</c>. | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 20 /// </para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 21 /// <para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 22 /// Сервис, в свою очередь, по окончанию выполнения операции (возможно с ошибкой), | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 23 /// использует методы <c>Resolve</c> либо <c>Reject</c> для оповещения клиетна о | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 24 /// выполнении обещания. | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 25 /// </para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 26 /// <para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 27 /// Если сервер успел выполнить обещание еще до того, как клиент на него подписался, | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 28 /// то в момент подписки клиента будут вызваны соответсвующие события в синхронном | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 29 /// режиме и клиент будет оповещен в любом случае. Иначе, обработчики добавляются в | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 30 /// список в порядке подписания и в этом же порядке они будут вызваны при выполнении | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 31 /// обещания. | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 32 /// </para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 33 /// <para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 34 /// Обрабатывая результаты обещания можно преобразовывать результаты либо инициировать | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 35 /// связанные асинхронные операции, которые также возвращают обещания. Для этого следует | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 36 /// использовать соответствующую форму методе <c>Then</c>. | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 37 /// </para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 38 /// <para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 39 /// Также хорошим правилом является то, что <c>Resolve</c> и <c>Reject</c> должен вызывать | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 40 /// только инициатор обещания иначе могут возникнуть противоречия. | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 41 /// </para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 42 /// </remarks> | 
| 25 | 43 public class Promise<T> : IPromise<T> { | 
| 2 | 44 | 
| 106 | 45 protected abstract class AbstractHandler : MTCustomQueueNode<AbstractHandler> { | 
| 46 public abstract void Resolve(T result); | |
| 47 public abstract void Reject(Exception error); | |
| 48 public abstract void Cancel(); | |
| 49 } | |
| 50 | |
| 51 protected class HandlerDescriptor<T2> : AbstractHandler { | |
| 52 | |
| 53 readonly Func<T,T2> m_resultHandler; | |
| 54 readonly Func<Exception,T2> m_errorHandler; | |
| 55 readonly Action m_cancellHandler; | |
| 56 readonly Promise<T2> m_medium; | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 57 | 
| 106 | 58 public HandlerDescriptor(Func<T,T2> resultHandler, Func<Exception,T2> errorHandler, Action cancelHandler, Promise<T2> medium) { | 
| 59 m_resultHandler = resultHandler; | |
| 60 m_errorHandler = errorHandler; | |
| 61 m_cancellHandler = cancelHandler; | |
| 62 m_medium = medium; | |
| 63 } | |
| 64 | |
| 65 public override void Resolve(T result) { | |
| 66 if (m_resultHandler != null) { | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 67 try { | 
| 106 | 68 if (m_medium != null) | 
| 69 m_medium.Resolve(m_resultHandler(result)); | |
| 70 else | |
| 71 m_resultHandler(result); | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 72 } catch (Exception e) { | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 73 Reject(e); | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 74 } | 
| 106 | 75 } else if(m_medium != null) | 
| 76 m_medium.Resolve(default(T2)); | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 77 } | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 78 | 
| 106 | 79 public override void Reject(Exception error) { | 
| 80 if (m_errorHandler != null) { | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 81 try { | 
| 106 | 82 var res = m_errorHandler(error); | 
| 83 if (m_medium != null) | |
| 84 m_medium.Resolve(res); | |
| 99 | 85 /*} catch (TransientPromiseException err2) { | 
| 72 | 86 if (medium != null) | 
| 99 | 87 medium.Reject(err2.InnerException);*/ | 
| 72 | 88 } catch (Exception err2) { | 
| 106 | 89 if (m_medium != null) | 
| 90 m_medium.Reject(err2); | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 91 } | 
| 106 | 92 } else if (m_medium != null) | 
| 93 m_medium.Reject(error); | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 94 } | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 95 | 
| 106 | 96 public override void Cancel() { | 
| 97 if (m_cancellHandler != null) { | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 98 try { | 
| 106 | 99 m_cancellHandler(); | 
| 72 | 100 } catch (Exception err) { | 
| 101 Reject(err); | |
| 102 return; | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 103 } | 
| 72 | 104 } | 
| 106 | 105 if (m_medium != null) | 
| 106 m_medium.Cancel(); | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 107 } | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 108 } | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 109 | 
| 71 | 110 const int UNRESOLVED_SATE = 0; | 
| 111 const int TRANSITIONAL_STATE = 1; | |
| 112 const int SUCCEEDED_STATE = 2; | |
| 113 const int REJECTED_STATE = 3; | |
| 114 const int CANCELLED_STATE = 4; | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 115 | 
| 101 | 116 int m_childrenCount; | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 117 int m_state; | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 118 T m_result; | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 119 Exception m_error; | 
| 9 | 120 | 
| 106 | 121 readonly MTCustomQueue<AbstractHandler> m_handlers = new MTCustomQueue<AbstractHandler>(); | 
| 122 //readonly MTQueue<AbstractHandler> m_handlers = new MTQueue<AbstractHandler>(); | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 123 | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 124 public Promise() { | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 125 } | 
| 2 | 126 | 
| 101 | 127 public Promise(IPromise parent) { | 
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 128 if (parent != null) | 
| 106 | 129 AddHandler<T>( | 
| 76 | 130 null, | 
| 131 null, | |
| 132 () => { | |
| 133 if (parent.IsExclusive) | |
| 134 parent.Cancel(); | |
| 135 }, | |
| 104 | 136 null, | 
| 137 false | |
| 76 | 138 ); | 
| 10 | 139 } | 
| 2 | 140 | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 141 bool BeginTransit() { | 
| 71 | 142 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE); | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 143 } | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 144 | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 145 void CompleteTransit(int state) { | 
| 71 | 146 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE)) | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 147 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 148 } | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 149 | 
| 25 | 150 void WaitTransition() { | 
| 71 | 151 while (m_state == TRANSITIONAL_STATE) { | 
| 80 | 152 Thread.MemoryBarrier(); | 
| 25 | 153 } | 
| 154 } | |
| 155 | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 156 public bool IsResolved { | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 157 get { | 
| 80 | 158 Thread.MemoryBarrier(); | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 159 return m_state > 1; | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 160 } | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 161 } | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 162 | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 163 public bool IsCancelled { | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 164 get { | 
| 80 | 165 Thread.MemoryBarrier(); | 
| 71 | 166 return m_state == CANCELLED_STATE; | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 167 } | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 168 } | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 169 | 
| 29 | 170 public Type PromiseType { | 
| 171 get { return typeof(T); } | |
| 172 } | |
| 173 | |
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 174 /// <summary> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 175 /// Выполняет обещание, сообщая об успешном выполнении. | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 176 /// </summary> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 177 /// <param name="result">Результат выполнения.</param> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 178 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 179 public void Resolve(T result) { | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 180 if (BeginTransit()) { | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 181 m_result = result; | 
| 71 | 182 CompleteTransit(SUCCEEDED_STATE); | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 183 OnStateChanged(); | 
| 25 | 184 } else { | 
| 185 WaitTransition(); | |
| 71 | 186 if (m_state != CANCELLED_STATE) | 
| 25 | 187 throw new InvalidOperationException("The promise is already resolved"); | 
| 188 } | |
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 189 } | 
| 2 | 190 | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 191 /// <summary> | 
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 192 /// Выполняет обещание, сообщая об успешном выполнении. Результатом выполнения будет пустое значения. | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 193 /// </summary> | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 194 /// <remarks> | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 195 /// Данный вариант удобен в случаях, когда интересен факт выполнения операции, нежели полученное значение. | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 196 /// </remarks> | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 197 public void Resolve() { | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 198 Resolve(default(T)); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 199 } | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 200 | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 201 /// <summary> | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 202 /// Выполняет обещание, сообщая об ошибке | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 203 /// </summary> | 
| 16 | 204 /// <remarks> | 
| 205 /// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков | |
| 206 /// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные | |
| 207 /// будут проигнорированы. | |
| 208 /// </remarks> | |
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 209 /// <param name="error">Исключение возникшее при выполнении операции</param> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 210 /// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 211 public void Reject(Exception error) { | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 212 if (BeginTransit()) { | 
| 99 | 213 m_error = error is TransientPromiseException ? error.InnerException : error; | 
| 71 | 214 CompleteTransit(REJECTED_STATE); | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 215 OnStateChanged(); | 
| 25 | 216 } else { | 
| 217 WaitTransition(); | |
| 71 | 218 if (m_state == SUCCEEDED_STATE) | 
| 25 | 219 throw new InvalidOperationException("The promise is already resolved"); | 
| 220 } | |
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 221 } | 
| 2 | 222 | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 223 /// <summary> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 224 /// Отменяет операцию, если это возможно. | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 225 /// </summary> | 
| 76 | 226 /// <remarks>Для определения была ли операция отменена следует использовать свойство <see cref="IsCancelled"/>.</remarks> | 
| 227 public void Cancel() { | |
| 101 | 228 if (BeginTransit()) { | 
| 71 | 229 CompleteTransit(CANCELLED_STATE); | 
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 230 OnStateChanged(); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 231 } | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 232 } | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 233 | 
| 76 | 234 /// <summary> | 
| 235 /// Последний обработчик в цепочки обещаний. | |
| 236 /// </summary> | |
| 237 /// <param name="success"></param> | |
| 238 /// <param name="error"></param> | |
| 239 /// <param name="cancel"></param> | |
| 240 /// <remarks> | |
| 241 /// <para> | |
| 242 /// Данный метод не создает связанного с текущим обещания и предназначен для окончания | |
| 243 /// фсинхронной цепочки. | |
| 244 /// </para> | |
| 245 /// <para> | |
| 246 /// Если данный метод вызвать несколько раз, либо добавить другие обработчики, то цепочка | |
| 247 /// не будет одиночной <see cref="IsExclusive"/> и, как следствие, будет невозможна отмена | |
| 248 /// всей цепи обещаний снизу (с самого последнего обещания). | |
| 249 /// </para> | |
| 250 /// </remarks> | |
| 104 | 251 public void On(Action<T> success, Action<Exception> error, Action cancel) { | 
| 75 | 252 if (success == null && error == null && cancel == null) | 
| 253 return; | |
| 254 | |
| 106 | 255 AddHandler( | 
| 256 success != null ? new Func<T,T>(x => { | |
| 257 success(x); | |
| 258 return x; | |
| 259 }) : null, | |
| 260 error != null ? new Func<Exception,T>(e => { | |
| 261 error(e); | |
| 75 | 262 return default(T); | 
| 106 | 263 }) : null, | 
| 264 cancel, | |
| 265 null, | |
| 266 false | |
| 267 ); | |
| 104 | 268 } | 
| 269 | |
| 270 public void On(Action<T> success, Action<Exception> error) { | |
| 271 On(success, error, null); | |
| 272 } | |
| 273 | |
| 274 public void On(Action<T> success) { | |
| 275 On(success, null, null); | |
| 75 | 276 } | 
| 277 | |
| 104 | 278 public void On(Action handler, PromiseEventType events) { | 
| 279 Safe.ArgumentNotNull(handler, "handler"); | |
| 75 | 280 | 
| 106 | 281 Func<T,T> success = events.HasFlag(PromiseEventType.Success) ? new Func<T,T>(x => { | 
| 282 handler(); | |
| 283 return x; | |
| 284 }) : null; | |
| 104 | 285 Func<Exception,T> error = events.HasFlag(PromiseEventType.Error) ? new Func<Exception,T>(e => { | 
| 286 handler(); | |
| 287 return default(T); | |
| 288 }) : null; | |
| 289 Action cancel = events.HasFlag(PromiseEventType.Cancelled) ? handler : null; | |
| 290 | |
| 291 AddHandler(success, error, cancel, null, false); | |
| 75 | 292 } | 
| 293 | |
| 101 | 294 public IPromise Error(Action<Exception> error) { | 
| 72 | 295 if (error == null) | 
| 296 return this; | |
| 297 | |
| 101 | 298 var medium = new Promise<T>(this); | 
| 72 | 299 | 
| 300 AddHandler( | |
| 301 null, | |
| 302 e => { | |
| 303 error(e); | |
| 304 return default(T); | |
| 305 }, | |
| 306 null, | |
| 104 | 307 medium, | 
| 308 true | |
| 72 | 309 ); | 
| 310 | |
| 311 return medium; | |
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 312 } | 
| 2 | 313 | 
| 11 | 314 /// <summary> | 
| 315 /// Handles error and allows to keep the promise. | |
| 316 /// </summary> | |
| 317 /// <remarks> | |
| 318 /// If the specified handler throws an exception, this exception will be used to reject the promise. | |
| 319 /// </remarks> | |
| 320 /// <param name="handler">The error handler which returns the result of the promise.</param> | |
| 321 /// <returns>New promise.</returns> | |
| 101 | 322 public IPromise<T> Error(Func<Exception,T> handler) { | 
| 11 | 323 if (handler == null) | 
| 324 return this; | |
| 325 | |
| 101 | 326 var medium = new Promise<T>(this); | 
| 11 | 327 | 
| 104 | 328 AddHandler(null, handler, null, medium, true); | 
| 11 | 329 | 
| 330 return medium; | |
| 331 } | |
| 332 | |
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 333 /// <summary> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 334 /// Позволяет преобразовать результат выполения операции к новому типу. | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 335 /// </summary> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 336 /// <typeparam name="TNew">Новый тип результата.</typeparam> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 337 /// <param name="mapper">Преобразование результата к новому типу.</param> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 338 /// <param name="error">Обработчик ошибки. Данный обработчик получит | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 339 /// исключение возникшее при выполнении операции.</param> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 340 /// <returns>Новое обещание, которое будет выполнено при выполнении исходного обещания.</returns> | 
| 96 | 341 /// <param name = "cancel"></param> | 
| 101 | 342 public IPromise<TNew> Then<TNew>(Func<T, TNew> mapper, Func<Exception,TNew> error, Action cancel) { | 
| 76 | 343 Safe.ArgumentNotNull(mapper, "mapper"); | 
| 344 | |
| 345 // создаем прицепленное обещание | |
| 101 | 346 var medium = new Promise<TNew>(this); | 
| 2 | 347 | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 348 AddHandler( | 
| 106 | 349 mapper, | 
| 350 error, | |
| 351 cancel, | |
| 352 medium, | |
| 104 | 353 true | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 354 ); | 
| 2 | 355 | 
| 76 | 356 return medium; | 
| 357 } | |
| 358 | |
| 101 | 359 public IPromise<TNew> Then<TNew>(Func<T, TNew> mapper, Func<Exception,TNew> error) { | 
| 76 | 360 return Then(mapper, error, null); | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 361 } | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 362 | 
| 101 | 363 public IPromise<TNew> Then<TNew>(Func<T, TNew> mapper) { | 
| 76 | 364 return Then(mapper, null, null); | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 365 } | 
| 2 | 366 | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 367 /// <summary> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 368 /// Сцепляет несколько аснхронных операций. Указанная асинхронная операция будет вызвана после | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 369 /// выполнения текущей, а результат текущей операции может быть использован для инициализации | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 370 /// новой операции. | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 371 /// </summary> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 372 /// <typeparam name="TNew">Тип результата указанной асинхронной операции.</typeparam> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 373 /// <param name="chained">Асинхронная операция, которая должна будет начаться после выполнения текущей.</param> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 374 /// <param name="error">Обработчик ошибки. Данный обработчик получит | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 375 /// исключение возникшее при выполнении текуещй операции.</param> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 376 /// <returns>Новое обещание, которое будет выполнено по окончанию указанной аснхронной операции.</returns> | 
| 96 | 377 /// <param name = "cancel"></param> | 
| 101 | 378 public IPromise<TNew> Chain<TNew>(Func<T, IPromise<TNew>> chained, Func<Exception,IPromise<TNew>> error, Action cancel) { | 
| 76 | 379 | 
| 380 Safe.ArgumentNotNull(chained, "chained"); | |
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 381 | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 382 // проблема в том, что на момент связывания еще не начата асинхронная операция, поэтому нужно | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 383 // создать посредника, к которому будут подвызяваться следующие обработчики. | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 384 // когда будет выполнена реальная асинхронная операция, она обратиться к посреднику, чтобы | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 385 // передать через него результаты работы. | 
| 101 | 386 var medium = new Promise<TNew>(this); | 
| 2 | 387 | 
| 106 | 388 Func<T,T> resultHandler = delegate(T result) { | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 389 if (medium.IsCancelled) | 
| 106 | 390 return default(T); | 
| 10 | 391 | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 392 var promise = chained(result); | 
| 10 | 393 | 
| 104 | 394 promise.On( | 
| 72 | 395 medium.Resolve, | 
| 76 | 396 medium.Reject, | 
| 397 () => medium.Reject(new OperationCanceledException()) // внешняя отмена связанной операции рассматривается как ошибка | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 398 ); | 
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 399 | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 400 // notify chained operation that it's not needed anymore | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 401 // порядок вызова Then, Cancelled важен, поскольку от этого | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 402 // зависит IsExclusive | 
| 104 | 403 medium.On( | 
| 101 | 404 null, | 
| 405 null, | |
| 406 () => { | |
| 407 if (promise.IsExclusive) | |
| 408 promise.Cancel(); | |
| 409 } | |
| 410 ); | |
| 106 | 411 | 
| 412 return default(T); | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 413 }; | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 414 | 
| 101 | 415 Func<Exception,T> errorHandler; | 
| 76 | 416 | 
| 417 if (error != null) | |
| 418 errorHandler = delegate(Exception e) { | |
| 72 | 419 try { | 
| 76 | 420 var promise = error(e); | 
| 421 | |
| 104 | 422 promise.On( | 
| 76 | 423 medium.Resolve, | 
| 424 medium.Reject, | |
| 425 () => medium.Reject(new OperationCanceledException()) // внешняя отмена связанной операции рассматривается как ошибка | |
| 426 ); | |
| 427 | |
| 428 // notify chained operation that it's not needed anymore | |
| 429 // порядок вызова Then, Cancelled важен, поскольку от этого | |
| 430 // зависит IsExclusive | |
| 431 medium.Cancelled(() => { | |
| 432 if (promise.IsExclusive) | |
| 433 promise.Cancel(); | |
| 434 }); | |
| 72 | 435 } catch (Exception e2) { | 
| 436 medium.Reject(e2); | |
| 437 } | |
| 76 | 438 return default(T); | 
| 439 }; | |
| 440 else | |
| 441 errorHandler = err => { | |
| 442 medium.Reject(err); | |
| 443 return default(T); | |
| 444 }; | |
| 445 | |
| 446 | |
| 447 Action cancelHandler; | |
| 448 if (cancel != null) | |
| 449 cancelHandler = () => { | |
| 450 if (cancel != null) | |
| 451 cancel(); | |
| 452 medium.Cancel(); | |
| 453 }; | |
| 454 else | |
| 455 cancelHandler = medium.Cancel; | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 456 | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 457 AddHandler( | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 458 resultHandler, | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 459 errorHandler, | 
| 76 | 460 cancelHandler, | 
| 104 | 461 null, | 
| 462 true | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 463 ); | 
| 2 | 464 | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 465 return medium; | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 466 } | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 467 | 
| 101 | 468 public IPromise<TNew> Chain<TNew>(Func<T, IPromise<TNew>> chained, Func<Exception,IPromise<TNew>> error) { | 
| 76 | 469 return Chain(chained, error, null); | 
| 470 } | |
| 471 | |
| 101 | 472 public IPromise<TNew> Chain<TNew>(Func<T, IPromise<TNew>> chained) { | 
| 76 | 473 return Chain(chained, null, null); | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 474 } | 
| 2 | 475 | 
| 26 | 476 public IPromise<T> Cancelled(Action handler) { | 
| 101 | 477 var medium = new Promise<T>(this); | 
| 104 | 478 AddHandler(null, null, handler, medium, false); | 
| 74 | 479 return medium; | 
| 10 | 480 } | 
| 481 | |
| 25 | 482 /// <summary> | 
| 483 /// Adds the specified handler for all cases (success, error, cancel) | |
| 484 /// </summary> | |
| 485 /// <param name="handler">The handler that will be called anyway</param> | |
| 486 /// <returns>self</returns> | |
| 76 | 487 public IPromise<T> Anyway(Action handler) { | 
| 488 Safe.ArgumentNotNull(handler, "handler"); | |
| 104 | 489 | 
| 490 var medium = new Promise<T>(this); | |
| 491 | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 492 AddHandler( | 
| 106 | 493 x => { | 
| 494 handler(); | |
| 495 return x; | |
| 496 }, | |
| 72 | 497 e => { | 
| 498 handler(); | |
| 499 throw new TransientPromiseException(e); | |
| 500 }, | |
| 501 handler, | |
| 104 | 502 medium, | 
| 503 true | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 504 ); | 
| 104 | 505 | 
| 506 return medium; | |
| 10 | 507 } | 
| 508 | |
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 509 /// <summary> | 
| 29 | 510 /// Преобразует результат обещания к нужному типу | 
| 511 /// </summary> | |
| 512 /// <typeparam name="T2"></typeparam> | |
| 513 /// <returns></returns> | |
| 514 public IPromise<T2> Cast<T2>() { | |
| 75 | 515 return Then(x => (T2)(object)x, null); | 
| 29 | 516 } | 
| 517 | |
| 518 /// <summary> | |
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 519 /// Дожидается отложенного обещания и в случае успеха, возвращает | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 520 /// его, результат, в противном случае бросает исключение. | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 521 /// </summary> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 522 /// <remarks> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 523 /// <para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 524 /// Если ожидание обещания было прервано по таймауту, это не значит, | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 525 /// что обещание было отменено или что-то в этом роде, это только | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 526 /// означает, что мы его не дождались, однако все зарегистрированные | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 527 /// обработчики, как были так остались и они будут вызваны, когда | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 528 /// обещание будет выполнено. | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 529 /// </para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 530 /// <para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 531 /// Такое поведение вполне оправдано поскольку таймаут может истечь | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 532 /// в тот момент, когда началась обработка цепочки обработчиков, и | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 533 /// к тому же текущее обещание может стоять в цепочке обещаний и его | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 534 /// отклонение может привести к непрогнозируемому результату. | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 535 /// </para> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 536 /// </remarks> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 537 /// <param name="timeout">Время ожидания</param> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 538 /// <returns>Результат выполнения обещания</returns> | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 539 public T Join(int timeout) { | 
| 10 | 540 var evt = new ManualResetEvent(false); | 
| 76 | 541 Anyway(() => evt.Set()); | 
| 2 | 542 | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 543 if (!evt.WaitOne(timeout, true)) | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 544 throw new TimeoutException(); | 
| 2 | 545 | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 546 switch (m_state) { | 
| 71 | 547 case SUCCEEDED_STATE: | 
| 10 | 548 return m_result; | 
| 71 | 549 case CANCELLED_STATE: | 
| 10 | 550 throw new OperationCanceledException(); | 
| 71 | 551 case REJECTED_STATE: | 
| 10 | 552 throw new TargetInvocationException(m_error); | 
| 553 default: | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 554 throw new ApplicationException(String.Format("Invalid promise state {0}", m_state)); | 
| 10 | 555 } | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 556 } | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 557 | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 558 public T Join() { | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 559 return Join(Timeout.Infinite); | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 560 } | 
| 2 | 561 | 
| 106 | 562 void AddHandler<T2>(Func<T,T2> success, Func<Exception,T2> error, Action cancel, Promise<T2> medium, bool inc) { | 
| 104 | 563 if (inc) | 
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 564 Interlocked.Increment(ref m_childrenCount); | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 565 | 
| 106 | 566 AbstractHandler handler = new HandlerDescriptor<T2>(success, error, cancel, medium); | 
| 2 | 567 | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 568 bool queued; | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 569 | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 570 if (!IsResolved) { | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 571 m_handlers.Enqueue(handler); | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 572 queued = true; | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 573 } else { | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 574 // the promise is in resolved state, just invoke the handled with minimum overhead | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 575 queued = false; | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 576 InvokeHandler(handler); | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 577 } | 
| 2 | 578 | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 579 if (queued && IsResolved && m_handlers.TryDequeue(out handler)) | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 580 // if the promise have been resolved while we was adding handler to the queue | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 581 // we can't guarantee that someone is still processing it | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 582 // therefore we will fetch a handler from the queue and execute it | 
| 27 | 583 // note that fetched handler may be not the one that we have added | 
| 584 // even we can fetch no handlers at all :) | |
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 585 InvokeHandler(handler); | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 586 } | 
| 2 | 587 | 
| 106 | 588 protected virtual void InvokeHandler(AbstractHandler handler) { | 
| 10 | 589 switch (m_state) { | 
| 71 | 590 case SUCCEEDED_STATE: | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 591 handler.Resolve(m_result); | 
| 10 | 592 break; | 
| 71 | 593 case REJECTED_STATE: | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 594 handler.Reject(m_error); | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 595 break; | 
| 71 | 596 case CANCELLED_STATE: | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 597 handler.Cancel(); | 
| 10 | 598 break; | 
| 599 default: | |
| 600 // do nothing | |
| 601 return; | |
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 602 } | 
| 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 603 } | 
| 2 | 604 | 
| 65 | 605 void OnStateChanged() { | 
| 106 | 606 AbstractHandler handler; | 
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 607 while (m_handlers.TryDequeue(out handler)) | 
| 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 608 InvokeHandler(handler); | 
| 11 | 609 } | 
| 610 | |
| 9 | 611 public bool IsExclusive { | 
| 612 get { | |
| 19 
e3935fdf59a2
Promise is rewritten to use interlocked operations instead of locks
 cin parents: 
16diff
changeset | 613 return m_childrenCount <= 1; | 
| 9 | 614 } | 
| 615 } | |
| 616 | |
| 25 | 617 /// <summary> | 
| 618 /// Объединяет несколько обещаний в одно, результатом которого является массив результатов других обещаний. | |
| 619 /// Если хотябы одно из переданных обещаний не будет выполнено, то новое обещение тоже не будет выполнено. | |
| 620 /// При отмене нового обещания, переданные обещания также будут отменены, если никто больше на них не подписан. | |
| 621 /// </summary> | |
| 622 /// <param name="promises">Список обещаний. Если список пустой, то результирующее обещание возвращается уже выполненным.</param> | |
| 623 /// <returns>Обещание объединяющее в себе результат переданных обещаний.</returns> | |
| 624 /// <exception cref="ArgumentNullException"><paramref name="promises"/> не может быть null</exception> | |
| 30 | 625 public static IPromise<T[]> CreateComposite(IList<IPromise<T>> promises) { | 
| 25 | 626 if (promises == null) | 
| 627 throw new ArgumentNullException(); | |
| 628 | |
| 629 // создаем аккумулятор для результатов и результирующее обещание | |
| 630 var result = new T[promises.Count]; | |
| 631 var promise = new Promise<T[]>(); | |
| 632 | |
| 633 // special case | |
| 634 if (promises.Count == 0) { | |
| 635 promise.Resolve(result); | |
| 636 return promise; | |
| 637 } | |
| 638 | |
| 639 int pending = promises.Count; | |
| 640 | |
| 641 for (int i = 0; i < promises.Count; i++) { | |
| 642 var dest = i; | |
| 643 | |
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 644 if (promises[i] != null) { | 
| 106 | 645 promises[i].On( | 
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 646 x => { | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 647 result[dest] = x; | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 648 if (Interlocked.Decrement(ref pending) == 0) | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 649 promise.Resolve(result); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 650 }, | 
| 106 | 651 promise.Reject | 
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 652 ); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 653 } else { | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 654 if (Interlocked.Decrement(ref pending) == 0) | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 655 promise.Resolve(result); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 656 } | 
| 25 | 657 } | 
| 658 | |
| 659 promise.Cancelled( | |
| 660 () => { | |
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 661 foreach (var d in promises) | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 662 if (d != null && d.IsExclusive) | 
| 25 | 663 d.Cancel(); | 
| 664 } | |
| 665 ); | |
| 666 | |
| 667 return promise; | |
| 668 } | |
| 669 | |
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 670 /// <summary> | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 671 /// Объединяет несколько обещаний в одно. Результирующее обещание будет выполнено при | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 672 /// выполнении всех указанных обещаний. При этом возвращаемые значения первичных обещаний | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 673 /// игнорируются. | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 674 /// </summary> | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 675 /// <param name="promises">Коллекция первичных обещаний, которые будут объеденены в одно.</param> | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 676 /// <returns>Новое обещание, объединяющее в себе переданные.</returns> | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 677 /// <remarks> | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 678 /// Если в коллекции встречаюься <c>null</c>, то они воспринимаются как выполненные обещания. | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 679 /// </remarks> | 
| 66 | 680 public static IPromise CreateComposite(ICollection<IPromise> promises) { | 
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 681 if (promises == null) | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 682 throw new ArgumentNullException(); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 683 if (promises.Count == 0) | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 684 return Promise<object>.ResultToPromise(null); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 685 | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 686 int countdown = promises.Count; | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 687 | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 688 var result = new Promise<object>(); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 689 | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 690 foreach (var d in promises) { | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 691 if (d == null) { | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 692 if (Interlocked.Decrement(ref countdown) == 0) | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 693 result.Resolve(null); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 694 } else { | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 695 d.Then(() => { | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 696 if (Interlocked.Decrement(ref countdown) == 0) | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 697 result.Resolve(null); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 698 }); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 699 } | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 700 } | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 701 | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 702 result.Cancelled(() => { | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 703 foreach (var d in promises) | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 704 if (d != null && d.IsExclusive) | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 705 d.Cancel(); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 706 }); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 707 | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 708 return result; | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 709 } | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 710 | 
| 25 | 711 public static Promise<T> ResultToPromise(T result) { | 
| 712 var p = new Promise<T>(); | |
| 713 p.Resolve(result); | |
| 714 return p; | |
| 715 } | |
| 716 | |
| 717 public static Promise<T> ExceptionToPromise(Exception error) { | |
| 718 if (error == null) | |
| 719 throw new ArgumentNullException(); | |
| 720 | |
| 721 var p = new Promise<T>(); | |
| 722 p.Reject(error); | |
| 723 return p; | |
| 724 } | |
| 725 | |
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 726 #region IPromiseBase explicit implementation | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 727 | 
| 101 | 728 IPromise IPromise.Then(Action success, Action<Exception> error, Action cancel) { | 
| 76 | 729 return Then( | 
| 106 | 730 success != null ? new Func<T,T>(x => { | 
| 731 success(); | |
| 732 return x; | |
| 733 }) : null, | |
| 101 | 734 error != null ? new Func<Exception,T>(e => { | 
| 76 | 735 error(e); | 
| 736 return default(T); | |
| 96 | 737 }) : null, | 
| 76 | 738 cancel | 
| 739 ); | |
| 740 } | |
| 741 | |
| 101 | 742 IPromise IPromise.Then(Action success, Action<Exception> error) { | 
| 76 | 743 return Then( | 
| 106 | 744 success != null ? new Func<T,T>(x => { | 
| 745 success(); | |
| 746 return x; | |
| 747 }) : null, | |
| 101 | 748 error != null ? new Func<Exception,T>(e => { | 
| 76 | 749 error(e); | 
| 750 return default(T); | |
| 96 | 751 }) : null | 
| 76 | 752 ); | 
| 753 } | |
| 754 | |
| 755 IPromise IPromise.Then(Action success) { | |
| 96 | 756 Safe.ArgumentNotNull(success, "success"); | 
| 106 | 757 return Then(x => { | 
| 758 success(); | |
| 759 return x; | |
| 760 }); | |
| 76 | 761 } | 
| 762 | |
| 101 | 763 IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) { | 
| 96 | 764 return ChainNoResult(chained, error, cancel); | 
| 765 } | |
| 766 | |
| 101 | 767 IPromise ChainNoResult(Func<IPromise> chained, Func<Exception,IPromise> error, Action cancel) { | 
| 104 | 768 Safe.ArgumentNotNull(chained, "chained"); | 
| 96 | 769 | 
| 101 | 770 var medium = new Promise<object>(this); | 
| 96 | 771 | 
| 106 | 772 Func<T,T> resultHandler = delegate { | 
| 104 | 773 if (medium.IsCancelled) | 
| 106 | 774 return default(T); | 
| 96 | 775 | 
| 104 | 776 var promise = chained(); | 
| 96 | 777 | 
| 104 | 778 promise.On( | 
| 779 medium.Resolve, | |
| 780 medium.Reject, | |
| 781 () => medium.Reject(new OperationCanceledException()) // внешняя отмена связанной операции рассматривается как ошибка | |
| 782 ); | |
| 96 | 783 | 
| 104 | 784 // notify chained operation that it's not needed anymore | 
| 785 // порядок вызова Then, Cancelled важен, поскольку от этого | |
| 786 // зависит IsExclusive | |
| 787 medium.Cancelled(() => { | |
| 788 if (promise.IsExclusive) | |
| 789 promise.Cancel(); | |
| 790 }); | |
| 106 | 791 | 
| 792 return default(T); | |
| 104 | 793 }; | 
| 96 | 794 | 
| 101 | 795 Func<Exception,T> errorHandler; | 
| 96 | 796 | 
| 104 | 797 if (error != null) | 
| 798 errorHandler = delegate(Exception e) { | |
| 96 | 799 try { | 
| 800 var promise = error(e); | |
| 801 | |
| 104 | 802 promise.On( | 
| 96 | 803 medium.Resolve, | 
| 804 medium.Reject, | |
| 805 () => medium.Reject(new OperationCanceledException()) // внешняя отмена связанной операции рассматривается как ошибка | |
| 806 ); | |
| 807 | |
| 808 // notify chained operation that it's not needed anymore | |
| 809 // порядок вызова Then, Cancelled важен, поскольку от этого | |
| 810 // зависит IsExclusive | |
| 811 medium.Cancelled(() => { | |
| 812 if (promise.IsExclusive) | |
| 813 promise.Cancel(); | |
| 814 }); | |
| 815 } catch (Exception e2) { | |
| 816 medium.Reject(e2); | |
| 817 } | |
| 818 return default(T); | |
| 819 }; | |
| 104 | 820 else | 
| 821 errorHandler = err => { | |
| 96 | 822 medium.Reject(err); | 
| 823 return default(T); | |
| 824 }; | |
| 825 | |
| 826 | |
| 104 | 827 Action cancelHandler; | 
| 828 if (cancel != null) | |
| 829 cancelHandler = () => { | |
| 96 | 830 if (cancel != null) | 
| 831 cancel(); | |
| 832 medium.Cancel(); | |
| 833 }; | |
| 104 | 834 else | 
| 835 cancelHandler = medium.Cancel; | |
| 96 | 836 | 
| 104 | 837 AddHandler( | 
| 838 resultHandler, | |
| 839 errorHandler, | |
| 840 cancelHandler, | |
| 841 null, | |
| 842 true | |
| 843 ); | |
| 96 | 844 | 
| 104 | 845 return medium; | 
| 96 | 846 } | 
| 104 | 847 | 
| 101 | 848 IPromise IPromise.Chain(Func<IPromise> chained, Func<Exception,IPromise> error) { | 
| 96 | 849 return ChainNoResult(chained, error, null); | 
| 850 } | |
| 104 | 851 | 
| 96 | 852 IPromise IPromise.Chain(Func<IPromise> chained) { | 
| 853 return ChainNoResult(chained, null, null); | |
| 104 | 854 } | 
| 96 | 855 | 
| 856 | |
| 104 | 857 void IPromise.On(Action success, Action<Exception> error, Action cancel) { | 
| 105 | 858 On(success != null ? new Action<T>(x => success()) : null, error, cancel); | 
| 76 | 859 } | 
| 860 | |
| 104 | 861 void IPromise.On(Action success, Action<Exception> error) { | 
| 862 On(x => success(), error, null); | |
| 76 | 863 } | 
| 864 | |
| 104 | 865 void IPromise.On(Action success) { | 
| 866 On(x => success(), null, null); | |
| 76 | 867 } | 
| 868 | |
| 101 | 869 IPromise IPromise.Error(Action<Exception> error) { | 
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 870 return Error(error); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 871 } | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 872 | 
| 76 | 873 IPromise IPromise.Anyway(Action handler) { | 
| 874 return Anyway(handler); | |
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 875 } | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 876 | 
| 66 | 877 IPromise IPromise.Cancelled(Action handler) { | 
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 878 return Cancelled(handler); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 879 } | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 880 | 
| 66 | 881 void IPromise.Join() { | 
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 882 Join(); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 883 } | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 884 | 
| 66 | 885 void IPromise.Join(int timeout) { | 
| 33 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 886 Join(timeout); | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 887 } | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 888 | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 889 #endregion | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 890 | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 891 | 
| 
b255e4aeef17
removed the reference to the parent from the promise object this allows
 cin parents: 
32diff
changeset | 892 | 
| 6 
dfa21d507bc5
*refactoring: Promise.Then now returns a new chained promise
 cin parents: 
2diff
changeset | 893 } | 
| 2 | 894 } | 
