aboutsummaryrefslogtreecommitdiff
path: root/node_modules/montage-user/core/promise.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/montage-user/core/promise.js')
-rwxr-xr-xnode_modules/montage-user/core/promise.js663
1 files changed, 663 insertions, 0 deletions
diff --git a/node_modules/montage-user/core/promise.js b/node_modules/montage-user/core/promise.js
new file mode 100755
index 00000000..aabe113d
--- /dev/null
+++ b/node_modules/montage-user/core/promise.js
@@ -0,0 +1,663 @@
1/* <copyright>
2 This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
3 No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
4 (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved.
5 </copyright> */
6
7// Scope:
8// * ES5
9// * speed and economy of memory before safety and securability
10// * run-time compatibility via thenability
11
12// TODO note the comps/promiseSend/sendPromise and argument order
13// changes from Q
14
15// This module is used during the boot-strapping, so it can be required as
16// a normal CommonJS module, but alternately bootstraps Montage if there
17// is a bootstrap global variable.
18(function (definition) {
19 if (typeof bootstrap !== "undefined") {
20 bootstrap("core/promise", definition);
21 } else if (typeof require !== "undefined") {
22 // module
23 definition(require, exports, module);
24 } else {
25 // global script
26 Q = {};
27 definition(function () {}, Q);
28 }
29})(function (require, exports, module) {
30
31"use strict";
32
33var TIMER;
34try {
35 // bootstrapping can't handle relative identifiers
36 TIMER = require("core/next-tick");
37} catch (exception) {
38 // in this case, node can't handle absolute identifiers
39 TIMER = require("./next-tick");
40}
41var nextTick = TIMER.nextTick;
42
43// merely ensures that the returned value can respond to
44// messages; does not guarantee a full promise API
45function toPromise(value) {
46 if (value && typeof value.sendPromise !== "undefined") {
47 return value;
48 } else if (value && typeof value.then !== "undefined") {
49 var deferred = Promise.defer();
50 value.then(function (value) {
51 deferred.resolve(value);
52 }, function (reason, error, rejection) {
53 if (rejection) {
54 deferred.resolve(rejection);
55 } else {
56 deferred.reject(reason, error);
57 }
58 });
59 return deferred.promise;
60 } else {
61 return Promise.fulfill(value);
62 }
63}
64
65var Creatable = Object.create(Object.prototype, {
66 create: {
67 value: function (descriptor) {
68 return Object.create(this, descriptor);
69 }
70 },
71});
72
73// Common implementation details of FulfilledPromise, RejectedPromise, and
74// DeferredPromise
75var AbstractPromise = Creatable.create({
76
77 // Common implementation of sendPromise for FulfiledPromise and
78 // RejectedPromise, but overridden by DeferredPromise to buffer
79 // messages instead of handling them.
80 sendPromise: {
81 value: function (resolve, op /*, ...args*/) {
82 var result;
83 try {
84 result = (this._handlers[op] || this._fallback)
85 .apply(this, arguments);
86 } catch (error) {
87 result = this.Promise.reject(error && error.message, error);
88 }
89 resolve(result);
90 }
91 },
92
93 // Defers polymorphically to toString
94 toSource: {
95 value: function () {
96 return this.toString();
97 }
98 }
99
100});
101
102// Basic implementation of the Promise object and prototypes for its
103// Fulfilled, Rejected, and Deferred subtypes. The mixin descriptors that
104// give the promise types useful methods like "then" are not applied until
105// .create() is used the first time to make the actual Promise export.
106var PrimordialPromise = Creatable.create({
107
108 create: {
109 value: function (descriptor, promiseDescriptor) {
110
111 // automatically subcreate each of the contained promise types
112 var creation = Object.create(this);
113 creation.DeferredPromise = this.DeferredPromise.create(promiseDescriptor);
114 creation.FulfilledPromise = this.FulfilledPromise.create(promiseDescriptor);
115 creation.RejectedPromise = this.RejectedPromise.create(promiseDescriptor);
116
117 if (descriptor) {
118 Object.defineProperties(creation, descriptor);
119 }
120
121 // create static reflections of all new promise methods
122 if (promiseDescriptor) {
123 Object.keys(promiseDescriptor).forEach(function (name) {
124 creation[name] = function (value) {
125 var args = Array.prototype.slice.call(arguments, 1);
126 var promise = this.ref(value);
127 return promise[name].apply(promise, args);
128 };
129 });
130 }
131
132 return creation;
133 }
134 },
135
136 isPromise: {
137 value: function (value) {
138 return value && typeof value.sendPromise !== "undefined";
139 }
140 },
141
142 ref: {
143 value: function (object) {
144 // if it is already a promise, wrap it to guarantee
145 // the full public API of this promise variety.
146 if (object && typeof object.sendPromise === "function") {
147 var deferred = this.defer();
148 deferred.resolve(object);
149 return deferred.promise;
150 // if it is at least a thenable duck-type, wrap it
151 } else if (object && typeof object.then === "function") {
152 var deferred = this.defer();
153 object.then(function (value) {
154 deferred.resolve(value);
155 }, function (reason, error, rejection) {
156 // if the thenable recognizes rejection
157 // forwarding, accept the given rejection
158 if (rejection) {
159 deferred.resolve(rejection);
160 // otherwise, handle reason and optional error forwarding
161 } else {
162 deferred.reject(reason, error);
163 }
164 })
165 return deferred.promise;
166 // if it is a fulfillment value, wrap it with a fulfillment
167 // promise
168 } else {
169 return this.fulfill(object);
170 }
171 }
172 },
173
174 fulfill: {
175 value: function (value) {
176 var self = Object.create(this.FulfilledPromise);
177 self._value = value;
178 self.Promise = this;
179 return self;
180 }
181 },
182
183 FulfilledPromise: {
184 value: AbstractPromise.create({
185
186 _handlers: {
187 value: {
188 then: function (r, o) {
189 return this._value;
190 },
191 get: function (r, o, key) {
192 return this._value[key];
193 },
194 put: function (r, o, key, value) {
195 return this._value[key] = value;
196 },
197 "delete": function (r, o, key) {
198 return delete this._value[key];
199 },
200 post: function (r, o, key, value) {
201 return this._value[key].apply(this._value, value);
202 },
203 apply: function (r, o, self, args) {
204 return this._value.apply(self, args);
205 },
206 keys: function (r, o) {
207 return Object.keys(this._value);
208 }
209 }
210 },
211
212 _fallback: {
213 value: function (callback, operator) {
214 return this.Promise.reject("Promise does not support operation: " + operator);
215 }
216 },
217
218 valueOf: {
219 value: function () {
220 return this._value;
221 }
222 },
223
224 toString: {
225 value: function () {
226 return '[object FulfilledPromise]';
227 }
228 }
229
230 })
</