Version 1
[yaffs-website] / node_modules / bluebird / js / release / using.js
1 "use strict";
2 module.exports = function (Promise, apiRejection, tryConvertToPromise,
3     createContext, INTERNAL, debug) {
4     var util = require("./util");
5     var TypeError = require("./errors").TypeError;
6     var inherits = require("./util").inherits;
7     var errorObj = util.errorObj;
8     var tryCatch = util.tryCatch;
9
10     function thrower(e) {
11         setTimeout(function(){throw e;}, 0);
12     }
13
14     function castPreservingDisposable(thenable) {
15         var maybePromise = tryConvertToPromise(thenable);
16         if (maybePromise !== thenable &&
17             typeof thenable._isDisposable === "function" &&
18             typeof thenable._getDisposer === "function" &&
19             thenable._isDisposable()) {
20             maybePromise._setDisposable(thenable._getDisposer());
21         }
22         return maybePromise;
23     }
24     function dispose(resources, inspection) {
25         var i = 0;
26         var len = resources.length;
27         var ret = new Promise(INTERNAL);
28         function iterator() {
29             if (i >= len) return ret._fulfill();
30             var maybePromise = castPreservingDisposable(resources[i++]);
31             if (maybePromise instanceof Promise &&
32                 maybePromise._isDisposable()) {
33                 try {
34                     maybePromise = tryConvertToPromise(
35                         maybePromise._getDisposer().tryDispose(inspection),
36                         resources.promise);
37                 } catch (e) {
38                     return thrower(e);
39                 }
40                 if (maybePromise instanceof Promise) {
41                     return maybePromise._then(iterator, thrower,
42                                               null, null, null);
43                 }
44             }
45             iterator();
46         }
47         iterator();
48         return ret;
49     }
50
51     function Disposer(data, promise, context) {
52         this._data = data;
53         this._promise = promise;
54         this._context = context;
55     }
56
57     Disposer.prototype.data = function () {
58         return this._data;
59     };
60
61     Disposer.prototype.promise = function () {
62         return this._promise;
63     };
64
65     Disposer.prototype.resource = function () {
66         if (this.promise().isFulfilled()) {
67             return this.promise().value();
68         }
69         return null;
70     };
71
72     Disposer.prototype.tryDispose = function(inspection) {
73         var resource = this.resource();
74         var context = this._context;
75         if (context !== undefined) context._pushContext();
76         var ret = resource !== null
77             ? this.doDispose(resource, inspection) : null;
78         if (context !== undefined) context._popContext();
79         this._promise._unsetDisposable();
80         this._data = null;
81         return ret;
82     };
83
84     Disposer.isDisposer = function (d) {
85         return (d != null &&
86                 typeof d.resource === "function" &&
87                 typeof d.tryDispose === "function");
88     };
89
90     function FunctionDisposer(fn, promise, context) {
91         this.constructor$(fn, promise, context);
92     }
93     inherits(FunctionDisposer, Disposer);
94
95     FunctionDisposer.prototype.doDispose = function (resource, inspection) {
96         var fn = this.data();
97         return fn.call(resource, resource, inspection);
98     };
99
100     function maybeUnwrapDisposer(value) {
101         if (Disposer.isDisposer(value)) {
102             this.resources[this.index]._setDisposable(value);
103             return value.promise();
104         }
105         return value;
106     }
107
108     function ResourceList(length) {
109         this.length = length;
110         this.promise = null;
111         this[length-1] = null;
112     }
113
114     ResourceList.prototype._resultCancelled = function() {
115         var len = this.length;
116         for (var i = 0; i < len; ++i) {
117             var item = this[i];
118             if (item instanceof Promise) {
119                 item.cancel();
120             }
121         }
122     };
123
124     Promise.using = function () {
125         var len = arguments.length;
126         if (len < 2) return apiRejection(
127                         "you must pass at least 2 arguments to Promise.using");
128         var fn = arguments[len - 1];
129         if (typeof fn !== "function") {
130             return apiRejection("expecting a function but got " + util.classString(fn));
131         }
132         var input;
133         var spreadArgs = true;
134         if (len === 2 && Array.isArray(arguments[0])) {
135             input = arguments[0];
136             len = input.length;
137             spreadArgs = false;
138         } else {
139             input = arguments;
140             len--;
141         }
142         var resources = new ResourceList(len);
143         for (var i = 0; i < len; ++i) {
144             var resource = input[i];
145             if (Disposer.isDisposer(resource)) {
146                 var disposer = resource;
147                 resource = resource.promise();
148                 resource._setDisposable(disposer);
149             } else {
150                 var maybePromise = tryConvertToPromise(resource);
151                 if (maybePromise instanceof Promise) {
152                     resource =
153                         maybePromise._then(maybeUnwrapDisposer, null, null, {
154                             resources: resources,
155                             index: i
156                     }, undefined);
157                 }
158             }
159             resources[i] = resource;
160         }
161
162         var reflectedResources = new Array(resources.length);
163         for (var i = 0; i < reflectedResources.length; ++i) {
164             reflectedResources[i] = Promise.resolve(resources[i]).reflect();
165         }
166
167         var resultPromise = Promise.all(reflectedResources)
168             .then(function(inspections) {
169                 for (var i = 0; i < inspections.length; ++i) {
170                     var inspection = inspections[i];
171                     if (inspection.isRejected()) {
172                         errorObj.e = inspection.error();
173                         return errorObj;
174                     } else if (!inspection.isFulfilled()) {
175                         resultPromise.cancel();
176                         return;
177                     }
178                     inspections[i] = inspection.value();
179                 }
180                 promise._pushContext();
181
182                 fn = tryCatch(fn);
183                 var ret = spreadArgs
184                     ? fn.apply(undefined, inspections) : fn(inspections);
185                 var promiseCreated = promise._popContext();
186                 debug.checkForgottenReturns(
187                     ret, promiseCreated, "Promise.using", promise);
188                 return ret;
189             });
190
191         var promise = resultPromise.lastly(function() {
192             var inspection = new Promise.PromiseInspection(resultPromise);
193             return dispose(resources, inspection);
194         });
195         resources.promise = promise;
196         promise._setOnCancel(resources);
197         return promise;
198     };
199
200     Promise.prototype._setDisposable = function (disposer) {
201         this._bitField = this._bitField | 131072;
202         this._disposer = disposer;
203     };
204
205     Promise.prototype._isDisposable = function () {
206         return (this._bitField & 131072) > 0;
207     };
208
209     Promise.prototype._getDisposer = function () {
210         return this._disposer;
211     };
212
213     Promise.prototype._unsetDisposable = function () {
214         this._bitField = this._bitField & (~131072);
215         this._disposer = undefined;
216     };
217
218     Promise.prototype.disposer = function (fn) {
219         if (typeof fn === "function") {
220             return new FunctionDisposer(fn, this, createContext());
221         }
222         throw new TypeError();
223     };
224
225 };