OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// This library adapts ES6 generators to implement Dart's async/await. | 5 /// This library adapts ES6 generators to implement Dart's async/await. |
6 /// It's designed to interact with Dart's Future/Stream and follow Dart | 6 /// It's designed to interact with Dart's Future/Stream and follow Dart |
7 /// async/await semantics. | 7 /// async/await semantics. |
8 /// See https://github.com/dart-lang/dev_compiler/issues/245 for ideas on | 8 /// See https://github.com/dart-lang/dev_compiler/issues/245 for ideas on |
9 /// reconciling Dart's Future and ES6 Promise. | 9 /// reconciling Dart's Future and ES6 Promise. |
10 /// Inspired by `co`: https://github.com/tj/co/blob/master/index.js, which is a | 10 /// Inspired by `co`: https://github.com/tj/co/blob/master/index.js, which is a |
(...skipping 27 matching lines...) Expand all Loading... |
38 return next(iter.throw(err)); | 38 return next(iter.throw(err)); |
39 } | 39 } |
40 function next(ret) { | 40 function next(ret) { |
41 if (ret.done) return ret.value; | 41 if (ret.done) return ret.value; |
42 // Checks if the awaited value is a Future. | 42 // Checks if the awaited value is a Future. |
43 let future = ret.value; | 43 let future = ret.value; |
44 if (!$instanceOf(future, ${getGenericClass(Future)})) { | 44 if (!$instanceOf(future, ${getGenericClass(Future)})) { |
45 future = $Future.value(future); | 45 future = $Future.value(future); |
46 } | 46 } |
47 // Chain the Future so `await` receives the Future's value. | 47 // Chain the Future so `await` receives the Future's value. |
48 return future.then($dynamicR)(onValue, {onError: onError}); | 48 return future.then($dynamic)(onValue, {onError: onError}); |
49 } | 49 } |
50 return ${getGenericClass(Future)}(T).new(function() { | 50 return ${getGenericClass(Future)}(T).new(function() { |
51 iter = $gen(...$args)[Symbol.iterator](); | 51 iter = $gen(...$args)[Symbol.iterator](); |
52 return onValue(); | 52 return onValue(); |
53 }); | 53 }); |
54 })()'''); | 54 })()'''); |
55 | 55 |
56 // Implementation inspired by _AsyncStarStreamController in | 56 // Implementation inspired by _AsyncStarStreamController in |
57 // dart-lang/sdk's runtime/lib/core_patch.dart | 57 // dart-lang/sdk's runtime/lib/core_patch.dart |
58 // | 58 // |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 // waiting on this Future. Make sure to prevent scheduling, and pass the | 157 // waiting on this Future. Make sure to prevent scheduling, and pass the |
158 // value back as the result of the `yield`. | 158 // value back as the result of the `yield`. |
159 // | 159 // |
160 // TODO(jmesserly): is the timing here correct? The assumption here is | 160 // TODO(jmesserly): is the timing here correct? The assumption here is |
161 // that we should schedule `await` in `async*` the same as in `async`. | 161 // that we should schedule `await` in `async*` the same as in `async`. |
162 this.isWaiting = true; | 162 this.isWaiting = true; |
163 let future = iter.value; | 163 let future = iter.value; |
164 if (!$instanceOf(future, ${getGenericClass(Future)})) { | 164 if (!$instanceOf(future, ${getGenericClass(Future)})) { |
165 future = $Future.value(future); | 165 future = $Future.value(future); |
166 } | 166 } |
167 return future.then($dynamicR)((x) => this.runBody(x), | 167 return future.then($dynamic)((x) => this.runBody(x), |
168 { onError: (e, s) => this.throwError(e, s) }); | 168 { onError: (e, s) => this.throwError(e, s) }); |
169 } | 169 } |
170 | 170 |
171 // Adds element to stream, returns true if the caller should terminate | 171 // Adds element to stream, returns true if the caller should terminate |
172 // execution of the generator. | 172 // execution of the generator. |
173 add(event) { | 173 add(event) { |
174 // If stream is cancelled, tell caller to exit the async generator. | 174 // If stream is cancelled, tell caller to exit the async generator. |
175 if (!this.controller.hasListener) return true; | 175 if (!this.controller.hasListener) return true; |
176 this.controller.add(event); | 176 this.controller.add(event); |
177 this.scheduleGenerator(); | 177 this.scheduleGenerator(); |
178 this.isSuspendedAtYield = true; | 178 this.isSuspendedAtYield = true; |
179 return false; | 179 return false; |
180 } | 180 } |
181 | 181 |
182 // Adds the elements of stream into this controller's stream. | 182 // Adds the elements of stream into this controller's stream. |
183 // The generator will be scheduled again when all of the | 183 // The generator will be scheduled again when all of the |
184 // elements of the added stream have been consumed. | 184 // elements of the added stream have been consumed. |
185 // Returns true if the caller should terminate | 185 // Returns true if the caller should terminate |
186 // execution of the generator. | 186 // execution of the generator. |
187 addStream(stream) { | 187 addStream(stream) { |
188 // If stream is cancelled, tell caller to exit the async generator. | 188 // If stream is cancelled, tell caller to exit the async generator. |
189 if (!this.controller.hasListener) return true; | 189 if (!this.controller.hasListener) return true; |
190 | 190 |
191 this.isAdding = true; | 191 this.isAdding = true; |
192 this.controller.addStream(stream, {cancelOnError: false}).then($dynamicR)( | 192 this.controller.addStream(stream, {cancelOnError: false}).then($dynamic)( |
193 () => { | 193 () => { |
194 this.isAdding = false; | 194 this.isAdding = false; |
195 this.scheduleGenerator(); | 195 this.scheduleGenerator(); |
196 }, { onError: (e, s) => this.throwError(e, s) }); | 196 }, { onError: (e, s) => this.throwError(e, s) }); |
197 } | 197 } |
198 | 198 |
199 throwError(error, stackTrace) { | 199 throwError(error, stackTrace) { |
200 try { | 200 try { |
201 this.iterator.throw(error); | 201 this.iterator.throw(error); |
202 } catch (e) { | 202 } catch (e) { |
(...skipping 12 matching lines...) Expand all Loading... |
215 this.controller.addError(error, stackTrace); | 215 this.controller.addError(error, stackTrace); |
216 } | 216 } |
217 } | 217 } |
218 '''); | 218 '''); |
219 | 219 |
220 /// Returns a Stream of T implemented by an async* function. */ | 220 /// Returns a Stream of T implemented by an async* function. */ |
221 /// | 221 /// |
222 asyncStar(gen, T, @rest args) => JS('', '''(() => { | 222 asyncStar(gen, T, @rest args) => JS('', '''(() => { |
223 return new $_AsyncStarStreamController($gen, $T, $args).controller.stream; | 223 return new $_AsyncStarStreamController($gen, $T, $args).controller.stream; |
224 })()'''); | 224 })()'''); |
OLD | NEW |