1 | var FiberMgr = require('./fiberManager');
|
2 | var Semaphore = require('./semaphore');
|
3 | var Config = require('./config');
|
4 | var defer = require('./defer');
|
5 | var await = require('../await/index');
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | var AsyncIterator = (function () {
|
12 |
|
13 | function AsyncIterator(runContext, semaphore, returnValue, acceptsCallback) {
|
14 | this._runContext = runContext;
|
15 | this._semaphore = semaphore;
|
16 | this._fiber = FiberMgr.create();
|
17 | this._returnValue = returnValue;
|
18 | this._acceptsCallback = acceptsCallback;
|
19 | }
|
20 |
|
21 | AsyncIterator.prototype.next = function (callback) {
|
22 | var _this = this;
|
23 |
|
24 | if (this._acceptsCallback) {
|
25 | this._runContext.callback = callback;
|
26 | }
|
27 | if (this._returnValue !== Config.NONE) {
|
28 | var resolver = defer();
|
29 | this._runContext.resolver = resolver;
|
30 | }
|
31 |
|
32 | if (FiberMgr.isExecutingInFiber())
|
33 | this._semaphore = Semaphore.unlimited;
|
34 |
|
35 | if (this._returnValue === Config.THUNK) {
|
36 | var thunk = function (done) {
|
37 | if (done)
|
38 | resolver.promise.then(function (val) { return done(null, val); }, function (err) { return done(err); });
|
39 | _this._semaphore.enter(function () { return _this._fiber.run(_this._runContext); });
|
40 | _this._runContext.done = function () { return _this._semaphore.leave(); };
|
41 | };
|
42 | }
|
43 | else {
|
44 | this._semaphore.enter(function () { return _this._fiber.run(_this._runContext); });
|
45 | this._runContext.done = function () { return _this._semaphore.leave(); };
|
46 | }
|
47 |
|
48 | switch (this._returnValue) {
|
49 | case Config.PROMISE: return resolver.promise;
|
50 | case Config.THUNK: return thunk;
|
51 | case Config.RESULT: return await(resolver.promise);
|
52 | case Config.NONE: return;
|
53 | }
|
54 | };
|
55 |
|
56 | AsyncIterator.prototype.forEach = function (callback, doneCallback) {
|
57 | var _this = this;
|
58 |
|
59 | var run, runCtx = this._runContext;
|
60 | if (this._returnValue === Config.RESULT)
|
61 | run = function () { return stepAwaited(function () { return _this.next(); }); };
|
62 | else if (this._returnValue === Config.THUNK)
|
63 | run = function () { return _this.next()(stepCallback); };
|
64 | else if (this._acceptsCallback)
|
65 | run = function () { return _this.next(stepCallback); };
|
66 | else
|
67 | run = function () { return _this.next().then(stepResolved, endOfIteration); };
|
68 |
|
69 | if (this._returnValue === Config.PROMISE || this._returnValue === Config.THUNK) {
|
70 | var doneResolver = defer();
|
71 | }
|
72 | if (!this._acceptsCallback)
|
73 | doneCallback = null;
|
74 |
|
75 | if (this._returnValue === Config.THUNK) {
|
76 | var thunk = function (done) {
|
77 | if (done)
|
78 | doneResolver.promise.then(function (val) { return done(null, val); }, function (err) { return done(err); });
|
79 | run();
|
80 | };
|
81 | }
|
82 | else {
|
83 | run();
|
84 | }
|
85 |
|
86 | switch (this._returnValue) {
|
87 | case Config.PROMISE: return doneResolver.promise;
|
88 | case Config.THUNK: return thunk;
|
89 | case Config.RESULT: return undefined;
|
90 | case Config.NONE: return undefined;
|
91 | }
|
92 |
|
93 | function stepAwaited(next) {
|
94 | try {
|
95 | while (true) {
|
96 | var item = next();
|
97 | if (item.done)
|
98 | return endOfIteration();
|
99 | callback(item.value);
|
100 | }
|
101 | }
|
102 | catch (err) {
|
103 | endOfIteration(err);
|
104 | throw err;
|
105 | }
|
106 | }
|
107 | function stepCallback(err, result) {
|
108 | if (err || result.done)
|
109 | return endOfIteration(err);
|
110 | callback(result.value);
|
111 | setImmediate(run);
|
112 | }
|
113 | function stepResolved(result) {
|
114 | if (result.done)
|
115 | return endOfIteration();
|
116 | callback(result.value);
|
117 | setImmediate(run);
|
118 | }
|
119 | function endOfIteration(err) {
|
120 | if (doneCallback)
|
121 | err ? doneCallback(err) : doneCallback();
|
122 | if (doneResolver) {
|
123 | if (FiberMgr.isExecutingInFiber()) {
|
124 | runCtx.resolver = doneResolver;
|
125 | }
|
126 | else {
|
127 | err ? doneResolver.reject(err) : doneResolver.resolve(null);
|
128 | }
|
129 | }
|
130 | }
|
131 | };
|
132 |
|
133 | AsyncIterator.prototype.destroy = function () {
|
134 | this._fiber = null;
|
135 | };
|
136 | return AsyncIterator;
|
137 | })();
|
138 | module.exports = AsyncIterator;
|
139 |
|
\ | No newline at end of file |