├── README.md ├── bower.json ├── composer.json ├── package.json ├── rsvp.min.js ├── rsvp.es.js └── rsvp.js /README.md: -------------------------------------------------------------------------------- 1 | RSVP.js 2 | ========= 3 | 4 | Shim repository for [RSVP.js](http://github.com/tildeio/rsvp.js). 5 | 6 | Package Managers 7 | ---------------- 8 | 9 | * [Bower](http://bower.io): `rsvp` 10 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rsvp.js", 3 | "version": "4.0.1", 4 | "homepage": "https://github.com/tildeio/rsvp.js", 5 | "authors": [ 6 | "Stefan Penner " 7 | ], 8 | "description": "A lightweight library that provides tools for organizing asynchronous code", 9 | "main": "rsvp.js", 10 | "keywords": [ 11 | "promise" 12 | ], 13 | "license": "MIT" 14 | } 15 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "components/rsvp.js", 3 | "description": "RSVP.js provides simple tools for organizing asynchronous code.", 4 | "type": "component", 5 | "homepage": "http://github.com/components/rsvp.js", 6 | "license": "MIT", 7 | "extra": { 8 | "component": { 9 | "scripts": [ 10 | "rsvp.js" 11 | ], 12 | "files": [ 13 | "rsvp.min.js", 14 | "rsvp.js" 15 | ] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rsvp", 3 | "namespace": "RSVP", 4 | "version": "4.0.1", 5 | "description": "A lightweight library that provides tools for organizing asynchronous code", 6 | "main": "rsvp.js", 7 | "files": [ 8 | "rsvp.js", 9 | "rsvp.min.js" 10 | ], 11 | "devDependencies": { 12 | }, 13 | "scripts": { 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/tildeio/rsvp.js.git", 18 | "dist": "git@github.com:components/rsvp.js.git" 19 | }, 20 | "bugs": { 21 | "url": "https://github.com/tildeio/rsvp.js/issues" 22 | }, 23 | "browser": { 24 | "vertx": false 25 | }, 26 | "keywords": [ 27 | "promises", 28 | "futures" 29 | ], 30 | "author": "Tilde, Inc. & Stefan Penner", 31 | "license": "MIT" 32 | } 33 | -------------------------------------------------------------------------------- /rsvp.min.js: -------------------------------------------------------------------------------- 1 | (function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.RSVP=t.RSVP||{})})(this,function(t){"use strict";function e(t){var e=t._promiseCallbacks;e||(e=t._promiseCallbacks={});return e}function r(t,e){if(2!==arguments.length)return Ot[t];Ot[t]=e}function n(t){var e=typeof t;return null!==t&&("object"===e||"function"===e)}function o(t){return"function"==typeof t}function i(t){return null!==t&&"object"==typeof t}function u(t){return null!==t&&"object"==typeof t}function s(){setTimeout(function(){for(var t=0;t2&&void 0!==arguments[2])||arguments[2],o=arguments[3];return J(this,t.call(this,e,r,n,o))}Q(e,t);e.prototype._init=function(t,e){this._result={};this._enumerate(e);0===this._remaining&&j(this.promise,this._result)};e.prototype._enumerate=function(t){var e=this.promise,r=[];for(var n in t)Dt.call(t,n)&&r.push({position:n,entry:t[n]});var o=r.length;this._remaining=o;for(var i=void 0,u=0;e._state===Tt&&u postsJSON 992 | values[1] // => commentsJSON 993 | 994 | return values; 995 | }); 996 | ``` 997 | 998 | @class RSVP.Promise 999 | @param {function} resolver 1000 | @param {String} label optional string for labeling the promise. 1001 | Useful for tooling. 1002 | @constructor 1003 | */ 1004 | 1005 | var Promise = function () { 1006 | function Promise(resolver, label) { 1007 | this._id = counter++; 1008 | this._label = label; 1009 | this._state = undefined; 1010 | this._result = undefined; 1011 | this._subscribers = []; 1012 | 1013 | config.instrument && instrument('created', this); 1014 | 1015 | if (noop !== resolver) { 1016 | typeof resolver !== 'function' && needsResolver(); 1017 | this instanceof Promise ? initializePromise(this, resolver) : needsNew(); 1018 | } 1019 | } 1020 | 1021 | Promise.prototype._onError = function _onError(reason) { 1022 | var _this = this; 1023 | 1024 | config.after(function () { 1025 | if (_this._onError) { 1026 | config.trigger('error', reason, _this._label); 1027 | } 1028 | }); 1029 | }; 1030 | 1031 | /** 1032 | `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same 1033 | as the catch block of a try/catch statement. 1034 | 1035 | ```js 1036 | function findAuthor(){ 1037 | throw new Error('couldn\'t find that author'); 1038 | } 1039 | 1040 | // synchronous 1041 | try { 1042 | findAuthor(); 1043 | } catch(reason) { 1044 | // something went wrong 1045 | } 1046 | 1047 | // async with promises 1048 | findAuthor().catch(function(reason){ 1049 | // something went wrong 1050 | }); 1051 | ``` 1052 | 1053 | @method catch 1054 | @param {Function} onRejection 1055 | @param {String} label optional string for labeling the promise. 1056 | Useful for tooling. 1057 | @return {Promise} 1058 | */ 1059 | 1060 | 1061 | Promise.prototype.catch = function _catch(onRejection, label) { 1062 | return this.then(undefined, onRejection, label); 1063 | }; 1064 | 1065 | /** 1066 | `finally` will be invoked regardless of the promise's fate just as native 1067 | try/catch/finally behaves 1068 | 1069 | Synchronous example: 1070 | 1071 | ```js 1072 | findAuthor() { 1073 | if (Math.random() > 0.5) { 1074 | throw new Error(); 1075 | } 1076 | return new Author(); 1077 | } 1078 | 1079 | try { 1080 | return findAuthor(); // succeed or fail 1081 | } catch(error) { 1082 | return findOtherAuthor(); 1083 | } finally { 1084 | // always runs 1085 | // doesn't affect the return value 1086 | } 1087 | ``` 1088 | 1089 | Asynchronous example: 1090 | 1091 | ```js 1092 | findAuthor().catch(function(reason){ 1093 | return findOtherAuthor(); 1094 | }).finally(function(){ 1095 | // author was either found, or not 1096 | }); 1097 | ``` 1098 | 1099 | @method finally 1100 | @param {Function} callback 1101 | @param {String} label optional string for labeling the promise. 1102 | Useful for tooling. 1103 | @return {Promise} 1104 | */ 1105 | 1106 | 1107 | Promise.prototype.finally = function _finally(callback, label) { 1108 | var promise = this; 1109 | var constructor = promise.constructor; 1110 | 1111 | return promise.then(function (value) { 1112 | return constructor.resolve(callback()).then(function () { 1113 | return value; 1114 | }); 1115 | }, function (reason) { 1116 | return constructor.resolve(callback()).then(function () { 1117 | throw reason; 1118 | }); 1119 | }, label); 1120 | }; 1121 | 1122 | return Promise; 1123 | }(); 1124 | 1125 | Promise.cast = resolve$1; // deprecated 1126 | Promise.all = all; 1127 | Promise.race = race; 1128 | Promise.resolve = resolve$1; 1129 | Promise.reject = reject$1; 1130 | 1131 | Promise.prototype._guidKey = guidKey; 1132 | 1133 | /** 1134 | The primary way of interacting with a promise is through its `then` method, 1135 | which registers callbacks to receive either a promise's eventual value or the 1136 | reason why the promise cannot be fulfilled. 1137 | 1138 | ```js 1139 | findUser().then(function(user){ 1140 | // user is available 1141 | }, function(reason){ 1142 | // user is unavailable, and you are given the reason why 1143 | }); 1144 | ``` 1145 | 1146 | Chaining 1147 | -------- 1148 | 1149 | The return value of `then` is itself a promise. This second, 'downstream' 1150 | promise is resolved with the return value of the first promise's fulfillment 1151 | or rejection handler, or rejected if the handler throws an exception. 1152 | 1153 | ```js 1154 | findUser().then(function (user) { 1155 | return user.name; 1156 | }, function (reason) { 1157 | return 'default name'; 1158 | }).then(function (userName) { 1159 | // If `findUser` fulfilled, `userName` will be the user's name, otherwise it 1160 | // will be `'default name'` 1161 | }); 1162 | 1163 | findUser().then(function (user) { 1164 | throw new Error('Found user, but still unhappy'); 1165 | }, function (reason) { 1166 | throw new Error('`findUser` rejected and we\'re unhappy'); 1167 | }).then(function (value) { 1168 | // never reached 1169 | }, function (reason) { 1170 | // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. 1171 | // If `findUser` rejected, `reason` will be '`findUser` rejected and we\'re unhappy'. 1172 | }); 1173 | ``` 1174 | If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. 1175 | 1176 | ```js 1177 | findUser().then(function (user) { 1178 | throw new PedagogicalException('Upstream error'); 1179 | }).then(function (value) { 1180 | // never reached 1181 | }).then(function (value) { 1182 | // never reached 1183 | }, function (reason) { 1184 | // The `PedgagocialException` is propagated all the way down to here 1185 | }); 1186 | ``` 1187 | 1188 | Assimilation 1189 | ------------ 1190 | 1191 | Sometimes the value you want to propagate to a downstream promise can only be 1192 | retrieved asynchronously. This can be achieved by returning a promise in the 1193 | fulfillment or rejection handler. The downstream promise will then be pending 1194 | until the returned promise is settled. This is called *assimilation*. 1195 | 1196 | ```js 1197 | findUser().then(function (user) { 1198 | return findCommentsByAuthor(user); 1199 | }).then(function (comments) { 1200 | // The user's comments are now available 1201 | }); 1202 | ``` 1203 | 1204 | If the assimliated promise rejects, then the downstream promise will also reject. 1205 | 1206 | ```js 1207 | findUser().then(function (user) { 1208 | return findCommentsByAuthor(user); 1209 | }).then(function (comments) { 1210 | // If `findCommentsByAuthor` fulfills, we'll have the value here 1211 | }, function (reason) { 1212 | // If `findCommentsByAuthor` rejects, we'll have the reason here 1213 | }); 1214 | ``` 1215 | 1216 | Simple Example 1217 | -------------- 1218 | 1219 | Synchronous Example 1220 | 1221 | ```javascript 1222 | let result; 1223 | 1224 | try { 1225 | result = findResult(); 1226 | // success 1227 | } catch(reason) { 1228 | // failure 1229 | } 1230 | ``` 1231 | 1232 | Errback Example 1233 | 1234 | ```js 1235 | findResult(function(result, err){ 1236 | if (err) { 1237 | // failure 1238 | } else { 1239 | // success 1240 | } 1241 | }); 1242 | ``` 1243 | 1244 | Promise Example; 1245 | 1246 | ```javascript 1247 | findResult().then(function(result){ 1248 | // success 1249 | }, function(reason){ 1250 | // failure 1251 | }); 1252 | ``` 1253 | 1254 | Advanced Example 1255 | -------------- 1256 | 1257 | Synchronous Example 1258 | 1259 | ```javascript 1260 | let author, books; 1261 | 1262 | try { 1263 | author = findAuthor(); 1264 | books = findBooksByAuthor(author); 1265 | // success 1266 | } catch(reason) { 1267 | // failure 1268 | } 1269 | ``` 1270 | 1271 | Errback Example 1272 | 1273 | ```js 1274 | 1275 | function foundBooks(books) { 1276 | 1277 | } 1278 | 1279 | function failure(reason) { 1280 | 1281 | } 1282 | 1283 | findAuthor(function(author, err){ 1284 | if (err) { 1285 | failure(err); 1286 | // failure 1287 | } else { 1288 | try { 1289 | findBoooksByAuthor(author, function(books, err) { 1290 | if (err) { 1291 | failure(err); 1292 | } else { 1293 | try { 1294 | foundBooks(books); 1295 | } catch(reason) { 1296 | failure(reason); 1297 | } 1298 | } 1299 | }); 1300 | } catch(error) { 1301 | failure(err); 1302 | } 1303 | // success 1304 | } 1305 | }); 1306 | ``` 1307 | 1308 | Promise Example; 1309 | 1310 | ```javascript 1311 | findAuthor(). 1312 | then(findBooksByAuthor). 1313 | then(function(books){ 1314 | // found books 1315 | }).catch(function(reason){ 1316 | // something went wrong 1317 | }); 1318 | ``` 1319 | 1320 | @method then 1321 | @param {Function} onFulfillment 1322 | @param {Function} onRejection 1323 | @param {String} label optional string for labeling the promise. 1324 | Useful for tooling. 1325 | @return {Promise} 1326 | */ 1327 | Promise.prototype.then = then; 1328 | 1329 | function Result() { 1330 | this.value = undefined; 1331 | } 1332 | 1333 | var ERROR = new Result(); 1334 | var GET_THEN_ERROR$1 = new Result(); 1335 | 1336 | function getThen$1(obj) { 1337 | try { 1338 | return obj.then; 1339 | } catch (error) { 1340 | ERROR.value = error; 1341 | return ERROR; 1342 | } 1343 | } 1344 | 1345 | function tryApply(f, s, a) { 1346 | try { 1347 | f.apply(s, a); 1348 | } catch (error) { 1349 | ERROR.value = error; 1350 | return ERROR; 1351 | } 1352 | } 1353 | 1354 | function makeObject(_, argumentNames) { 1355 | var obj = {}; 1356 | var length = _.length; 1357 | var args = new Array(length); 1358 | 1359 | for (var x = 0; x < length; x++) { 1360 | args[x] = _[x]; 1361 | } 1362 | 1363 | for (var i = 0; i < argumentNames.length; i++) { 1364 | var name = argumentNames[i]; 1365 | obj[name] = args[i + 1]; 1366 | } 1367 | 1368 | return obj; 1369 | } 1370 | 1371 | function arrayResult(_) { 1372 | var length = _.length; 1373 | var args = new Array(length - 1); 1374 | 1375 | for (var i = 1; i < length; i++) { 1376 | args[i - 1] = _[i]; 1377 | } 1378 | 1379 | return args; 1380 | } 1381 | 1382 | function wrapThenable(then, promise) { 1383 | return { 1384 | then: function (onFulFillment, onRejection) { 1385 | return then.call(promise, onFulFillment, onRejection); 1386 | } 1387 | }; 1388 | } 1389 | 1390 | /** 1391 | `RSVP.denodeify` takes a 'node-style' function and returns a function that 1392 | will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the 1393 | browser when you'd prefer to use promises over using callbacks. For example, 1394 | `denodeify` transforms the following: 1395 | 1396 | ```javascript 1397 | let fs = require('fs'); 1398 | 1399 | fs.readFile('myfile.txt', function(err, data){ 1400 | if (err) return handleError(err); 1401 | handleData(data); 1402 | }); 1403 | ``` 1404 | 1405 | into: 1406 | 1407 | ```javascript 1408 | let fs = require('fs'); 1409 | let readFile = RSVP.denodeify(fs.readFile); 1410 | 1411 | readFile('myfile.txt').then(handleData, handleError); 1412 | ``` 1413 | 1414 | If the node function has multiple success parameters, then `denodeify` 1415 | just returns the first one: 1416 | 1417 | ```javascript 1418 | let request = RSVP.denodeify(require('request')); 1419 | 1420 | request('http://example.com').then(function(res) { 1421 | // ... 1422 | }); 1423 | ``` 1424 | 1425 | However, if you need all success parameters, setting `denodeify`'s 1426 | second parameter to `true` causes it to return all success parameters 1427 | as an array: 1428 | 1429 | ```javascript 1430 | let request = RSVP.denodeify(require('request'), true); 1431 | 1432 | request('http://example.com').then(function(result) { 1433 | // result[0] -> res 1434 | // result[1] -> body 1435 | }); 1436 | ``` 1437 | 1438 | Or if you pass it an array with names it returns the parameters as a hash: 1439 | 1440 | ```javascript 1441 | let request = RSVP.denodeify(require('request'), ['res', 'body']); 1442 | 1443 | request('http://example.com').then(function(result) { 1444 | // result.res 1445 | // result.body 1446 | }); 1447 | ``` 1448 | 1449 | Sometimes you need to retain the `this`: 1450 | 1451 | ```javascript 1452 | let app = require('express')(); 1453 | let render = RSVP.denodeify(app.render.bind(app)); 1454 | ``` 1455 | 1456 | The denodified function inherits from the original function. It works in all 1457 | environments, except IE 10 and below. Consequently all properties of the original 1458 | function are available to you. However, any properties you change on the 1459 | denodeified function won't be changed on the original function. Example: 1460 | 1461 | ```javascript 1462 | let request = RSVP.denodeify(require('request')), 1463 | cookieJar = request.jar(); // <- Inheritance is used here 1464 | 1465 | request('http://example.com', {jar: cookieJar}).then(function(res) { 1466 | // cookieJar.cookies holds now the cookies returned by example.com 1467 | }); 1468 | ``` 1469 | 1470 | Using `denodeify` makes it easier to compose asynchronous operations instead 1471 | of using callbacks. For example, instead of: 1472 | 1473 | ```javascript 1474 | let fs = require('fs'); 1475 | 1476 | fs.readFile('myfile.txt', function(err, data){ 1477 | if (err) { ... } // Handle error 1478 | fs.writeFile('myfile2.txt', data, function(err){ 1479 | if (err) { ... } // Handle error 1480 | console.log('done') 1481 | }); 1482 | }); 1483 | ``` 1484 | 1485 | you can chain the operations together using `then` from the returned promise: 1486 | 1487 | ```javascript 1488 | let fs = require('fs'); 1489 | let readFile = RSVP.denodeify(fs.readFile); 1490 | let writeFile = RSVP.denodeify(fs.writeFile); 1491 | 1492 | readFile('myfile.txt').then(function(data){ 1493 | return writeFile('myfile2.txt', data); 1494 | }).then(function(){ 1495 | console.log('done') 1496 | }).catch(function(error){ 1497 | // Handle error 1498 | }); 1499 | ``` 1500 | 1501 | @method denodeify 1502 | @static 1503 | @for RSVP 1504 | @param {Function} nodeFunc a 'node-style' function that takes a callback as 1505 | its last argument. The callback expects an error to be passed as its first 1506 | argument (if an error occurred, otherwise null), and the value from the 1507 | operation as its second argument ('function(err, value){ }'). 1508 | @param {Boolean|Array} [options] An optional paramter that if set 1509 | to `true` causes the promise to fulfill with the callback's success arguments 1510 | as an array. This is useful if the node function has multiple success 1511 | paramters. If you set this paramter to an array with names, the promise will 1512 | fulfill with a hash with these names as keys and the success parameters as 1513 | values. 1514 | @return {Function} a function that wraps `nodeFunc` to return an 1515 | `RSVP.Promise` 1516 | @static 1517 | */ 1518 | function denodeify(nodeFunc, options) { 1519 | var fn = function () { 1520 | var self = this; 1521 | var l = arguments.length; 1522 | var args = new Array(l + 1); 1523 | var promiseInput = false; 1524 | 1525 | for (var i = 0; i < l; ++i) { 1526 | var arg = arguments[i]; 1527 | 1528 | if (!promiseInput) { 1529 | // TODO: clean this up 1530 | promiseInput = needsPromiseInput(arg); 1531 | if (promiseInput === GET_THEN_ERROR$1) { 1532 | var p = new Promise(noop); 1533 | reject(p, GET_THEN_ERROR$1.value); 1534 | return p; 1535 | } else if (promiseInput && promiseInput !== true) { 1536 | arg = wrapThenable(promiseInput, arg); 1537 | } 1538 | } 1539 | args[i] = arg; 1540 | } 1541 | 1542 | var promise = new Promise(noop); 1543 | 1544 | args[l] = function (err, val) { 1545 | if (err) reject(promise, err);else if (options === undefined) resolve(promise, val);else if (options === true) resolve(promise, arrayResult(arguments));else if (Array.isArray(options)) resolve(promise, makeObject(arguments, options));else resolve(promise, val); 1546 | }; 1547 | 1548 | if (promiseInput) { 1549 | return handlePromiseInput(promise, args, nodeFunc, self); 1550 | } else { 1551 | return handleValueInput(promise, args, nodeFunc, self); 1552 | } 1553 | }; 1554 | 1555 | fn.__proto__ = nodeFunc; 1556 | 1557 | return fn; 1558 | } 1559 | 1560 | function handleValueInput(promise, args, nodeFunc, self) { 1561 | var result = tryApply(nodeFunc, self, args); 1562 | if (result === ERROR) { 1563 | reject(promise, result.value); 1564 | } 1565 | return promise; 1566 | } 1567 | 1568 | function handlePromiseInput(promise, args, nodeFunc, self) { 1569 | return Promise.all(args).then(function (args) { 1570 | var result = tryApply(nodeFunc, self, args); 1571 | if (result === ERROR) { 1572 | reject(promise, result.value); 1573 | } 1574 | return promise; 1575 | }); 1576 | } 1577 | 1578 | function needsPromiseInput(arg) { 1579 | if (arg && typeof arg === 'object') { 1580 | if (arg.constructor === Promise) { 1581 | return true; 1582 | } else { 1583 | return getThen$1(arg); 1584 | } 1585 | } else { 1586 | return false; 1587 | } 1588 | } 1589 | 1590 | /** 1591 | This is a convenient alias for `RSVP.Promise.all`. 1592 | 1593 | @method all 1594 | @static 1595 | @for RSVP 1596 | @param {Array} array Array of promises. 1597 | @param {String} label An optional label. This is useful 1598 | for tooling. 1599 | */ 1600 | function all$1(array, label) { 1601 | return Promise.all(array, label); 1602 | } 1603 | 1604 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 1605 | 1606 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 1607 | 1608 | var AllSettled = function (_Enumerator) { 1609 | _inherits(AllSettled, _Enumerator); 1610 | 1611 | function AllSettled(Constructor, entries, label) { 1612 | return _possibleConstructorReturn(this, _Enumerator.call(this, Constructor, entries, false /* don't abort on reject */, label)); 1613 | } 1614 | 1615 | return AllSettled; 1616 | }(Enumerator); 1617 | 1618 | AllSettled.prototype._setResultAt = setSettledResult; 1619 | 1620 | /** 1621 | `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing 1622 | a fail-fast method, it waits until all the promises have returned and 1623 | shows you all the results. This is useful if you want to handle multiple 1624 | promises' failure states together as a set. 1625 | Returns a promise that is fulfilled when all the given promises have been 1626 | settled. The return promise is fulfilled with an array of the states of 1627 | the promises passed into the `promises` array argument. 1628 | Each state object will either indicate fulfillment or rejection, and 1629 | provide the corresponding value or reason. The states will take one of 1630 | the following formats: 1631 | ```javascript 1632 | { state: 'fulfilled', value: value } 1633 | or 1634 | { state: 'rejected', reason: reason } 1635 | ``` 1636 | Example: 1637 | ```javascript 1638 | let promise1 = RSVP.Promise.resolve(1); 1639 | let promise2 = RSVP.Promise.reject(new Error('2')); 1640 | let promise3 = RSVP.Promise.reject(new Error('3')); 1641 | let promises = [ promise1, promise2, promise3 ]; 1642 | RSVP.allSettled(promises).then(function(array){ 1643 | // array == [ 1644 | // { state: 'fulfilled', value: 1 }, 1645 | // { state: 'rejected', reason: Error }, 1646 | // { state: 'rejected', reason: Error } 1647 | // ] 1648 | // Note that for the second item, reason.message will be '2', and for the 1649 | // third item, reason.message will be '3'. 1650 | }, function(error) { 1651 | // Not run. (This block would only be called if allSettled had failed, 1652 | // for instance if passed an incorrect argument type.) 1653 | }); 1654 | ``` 1655 | @method allSettled 1656 | @static 1657 | @for RSVP 1658 | @param {Array} entries 1659 | @param {String} label - optional string that describes the promise. 1660 | Useful for tooling. 1661 | @return {Promise} promise that is fulfilled with an array of the settled 1662 | states of the constituent promises. 1663 | */ 1664 | 1665 | function allSettled(entries, label) { 1666 | if (!Array.isArray(entries)) { 1667 | return Promise.reject(new TypeError("Promise.allSettled must be called with an array"), label); 1668 | } 1669 | 1670 | return new AllSettled(Promise, entries, label).promise; 1671 | } 1672 | 1673 | /** 1674 | This is a convenient alias for `RSVP.Promise.race`. 1675 | 1676 | @method race 1677 | @static 1678 | @for RSVP 1679 | @param {Array} array Array of promises. 1680 | @param {String} label An optional label. This is useful 1681 | for tooling. 1682 | */ 1683 | function race$1(array, label) { 1684 | return Promise.race(array, label); 1685 | } 1686 | 1687 | function _possibleConstructorReturn$1(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 1688 | 1689 | function _inherits$1(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 1690 | 1691 | var hasOwnProperty = Object.prototype.hasOwnProperty; 1692 | 1693 | var PromiseHash = function (_Enumerator) { 1694 | _inherits$1(PromiseHash, _Enumerator); 1695 | 1696 | function PromiseHash(Constructor, object) { 1697 | var abortOnReject = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; 1698 | var label = arguments[3]; 1699 | return _possibleConstructorReturn$1(this, _Enumerator.call(this, Constructor, object, abortOnReject, label)); 1700 | } 1701 | 1702 | PromiseHash.prototype._init = function _init(Constructor, object) { 1703 | this._result = {}; 1704 | 1705 | this._enumerate(object); 1706 | if (this._remaining === 0) { 1707 | fulfill(this.promise, this._result); 1708 | } 1709 | }; 1710 | 1711 | PromiseHash.prototype._enumerate = function _enumerate(input) { 1712 | var promise = this.promise; 1713 | var results = []; 1714 | 1715 | for (var key in input) { 1716 | if (hasOwnProperty.call(input, key)) { 1717 | results.push({ 1718 | position: key, 1719 | entry: input[key] 1720 | }); 1721 | } 1722 | } 1723 | 1724 | var length = results.length; 1725 | this._remaining = length; 1726 | var result = void 0; 1727 | 1728 | for (var i = 0; promise._state === PENDING && i < length; i++) { 1729 | result = results[i]; 1730 | this._eachEntry(result.entry, result.position); 1731 | } 1732 | }; 1733 | 1734 | return PromiseHash; 1735 | }(Enumerator); 1736 | 1737 | /** 1738 | `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array 1739 | for its `promises` argument. 1740 | 1741 | Returns a promise that is fulfilled when all the given promises have been 1742 | fulfilled, or rejected if any of them become rejected. The returned promise 1743 | is fulfilled with a hash that has the same key names as the `promises` object 1744 | argument. If any of the values in the object are not promises, they will 1745 | simply be copied over to the fulfilled object. 1746 | 1747 | Example: 1748 | 1749 | ```javascript 1750 | let promises = { 1751 | myPromise: RSVP.resolve(1), 1752 | yourPromise: RSVP.resolve(2), 1753 | theirPromise: RSVP.resolve(3), 1754 | notAPromise: 4 1755 | }; 1756 | 1757 | RSVP.hash(promises).then(function(hash){ 1758 | // hash here is an object that looks like: 1759 | // { 1760 | // myPromise: 1, 1761 | // yourPromise: 2, 1762 | // theirPromise: 3, 1763 | // notAPromise: 4 1764 | // } 1765 | }); 1766 | ```` 1767 | 1768 | If any of the `promises` given to `RSVP.hash` are rejected, the first promise 1769 | that is rejected will be given as the reason to the rejection handler. 1770 | 1771 | Example: 1772 | 1773 | ```javascript 1774 | let promises = { 1775 | myPromise: RSVP.resolve(1), 1776 | rejectedPromise: RSVP.reject(new Error('rejectedPromise')), 1777 | anotherRejectedPromise: RSVP.reject(new Error('anotherRejectedPromise')), 1778 | }; 1779 | 1780 | RSVP.hash(promises).then(function(hash){ 1781 | // Code here never runs because there are rejected promises! 1782 | }, function(reason) { 1783 | // reason.message === 'rejectedPromise' 1784 | }); 1785 | ``` 1786 | 1787 | An important note: `RSVP.hash` is intended for plain JavaScript objects that 1788 | are just a set of keys and values. `RSVP.hash` will NOT preserve prototype 1789 | chains. 1790 | 1791 | Example: 1792 | 1793 | ```javascript 1794 | function MyConstructor(){ 1795 | this.example = RSVP.resolve('Example'); 1796 | } 1797 | 1798 | MyConstructor.prototype = { 1799 | protoProperty: RSVP.resolve('Proto Property') 1800 | }; 1801 | 1802 | let myObject = new MyConstructor(); 1803 | 1804 | RSVP.hash(myObject).then(function(hash){ 1805 | // protoProperty will not be present, instead you will just have an 1806 | // object that looks like: 1807 | // { 1808 | // example: 'Example' 1809 | // } 1810 | // 1811 | // hash.hasOwnProperty('protoProperty'); // false 1812 | // 'undefined' === typeof hash.protoProperty 1813 | }); 1814 | ``` 1815 | 1816 | @method hash 1817 | @static 1818 | @for RSVP 1819 | @param {Object} object 1820 | @param {String} label optional string that describes the promise. 1821 | Useful for tooling. 1822 | @return {Promise} promise that is fulfilled when all properties of `promises` 1823 | have been fulfilled, or rejected if any of them become rejected. 1824 | */ 1825 | function hash(object, label) { 1826 | if (!isObject(object)) { 1827 | return Promise.reject(new TypeError("Promise.hash must be called with an object"), label); 1828 | } 1829 | 1830 | return new PromiseHash(Promise, object, label).promise; 1831 | } 1832 | 1833 | function _possibleConstructorReturn$2(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 1834 | 1835 | function _inherits$2(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 1836 | 1837 | var HashSettled = function (_PromiseHash) { 1838 | _inherits$2(HashSettled, _PromiseHash); 1839 | 1840 | function HashSettled(Constructor, object, label) { 1841 | return _possibleConstructorReturn$2(this, _PromiseHash.call(this, Constructor, object, false, label)); 1842 | } 1843 | 1844 | return HashSettled; 1845 | }(PromiseHash); 1846 | 1847 | HashSettled.prototype._setResultAt = setSettledResult; 1848 | 1849 | /** 1850 | `RSVP.hashSettled` is similar to `RSVP.allSettled`, but takes an object 1851 | instead of an array for its `promises` argument. 1852 | 1853 | Unlike `RSVP.all` or `RSVP.hash`, which implement a fail-fast method, 1854 | but like `RSVP.allSettled`, `hashSettled` waits until all the 1855 | constituent promises have returned and then shows you all the results 1856 | with their states and values/reasons. This is useful if you want to 1857 | handle multiple promises' failure states together as a set. 1858 | 1859 | Returns a promise that is fulfilled when all the given promises have been 1860 | settled, or rejected if the passed parameters are invalid. 1861 | 1862 | The returned promise is fulfilled with a hash that has the same key names as 1863 | the `promises` object argument. If any of the values in the object are not 1864 | promises, they will be copied over to the fulfilled object and marked with state 1865 | 'fulfilled'. 1866 | 1867 | Example: 1868 | 1869 | ```javascript 1870 | let promises = { 1871 | myPromise: RSVP.Promise.resolve(1), 1872 | yourPromise: RSVP.Promise.resolve(2), 1873 | theirPromise: RSVP.Promise.resolve(3), 1874 | notAPromise: 4 1875 | }; 1876 | 1877 | RSVP.hashSettled(promises).then(function(hash){ 1878 | // hash here is an object that looks like: 1879 | // { 1880 | // myPromise: { state: 'fulfilled', value: 1 }, 1881 | // yourPromise: { state: 'fulfilled', value: 2 }, 1882 | // theirPromise: { state: 'fulfilled', value: 3 }, 1883 | // notAPromise: { state: 'fulfilled', value: 4 } 1884 | // } 1885 | }); 1886 | ``` 1887 | 1888 | If any of the `promises` given to `RSVP.hash` are rejected, the state will 1889 | be set to 'rejected' and the reason for rejection provided. 1890 | 1891 | Example: 1892 | 1893 | ```javascript 1894 | let promises = { 1895 | myPromise: RSVP.Promise.resolve(1), 1896 | rejectedPromise: RSVP.Promise.reject(new Error('rejection')), 1897 | anotherRejectedPromise: RSVP.Promise.reject(new Error('more rejection')), 1898 | }; 1899 | 1900 | RSVP.hashSettled(promises).then(function(hash){ 1901 | // hash here is an object that looks like: 1902 | // { 1903 | // myPromise: { state: 'fulfilled', value: 1 }, 1904 | // rejectedPromise: { state: 'rejected', reason: Error }, 1905 | // anotherRejectedPromise: { state: 'rejected', reason: Error }, 1906 | // } 1907 | // Note that for rejectedPromise, reason.message == 'rejection', 1908 | // and for anotherRejectedPromise, reason.message == 'more rejection'. 1909 | }); 1910 | ``` 1911 | 1912 | An important note: `RSVP.hashSettled` is intended for plain JavaScript objects that 1913 | are just a set of keys and values. `RSVP.hashSettled` will NOT preserve prototype 1914 | chains. 1915 | 1916 | Example: 1917 | 1918 | ```javascript 1919 | function MyConstructor(){ 1920 | this.example = RSVP.Promise.resolve('Example'); 1921 | } 1922 | 1923 | MyConstructor.prototype = { 1924 | protoProperty: RSVP.Promise.resolve('Proto Property') 1925 | }; 1926 | 1927 | let myObject = new MyConstructor(); 1928 | 1929 | RSVP.hashSettled(myObject).then(function(hash){ 1930 | // protoProperty will not be present, instead you will just have an 1931 | // object that looks like: 1932 | // { 1933 | // example: { state: 'fulfilled', value: 'Example' } 1934 | // } 1935 | // 1936 | // hash.hasOwnProperty('protoProperty'); // false 1937 | // 'undefined' === typeof hash.protoProperty 1938 | }); 1939 | ``` 1940 | 1941 | @method hashSettled 1942 | @for RSVP 1943 | @param {Object} object 1944 | @param {String} label optional string that describes the promise. 1945 | Useful for tooling. 1946 | @return {Promise} promise that is fulfilled when when all properties of `promises` 1947 | have been settled. 1948 | @static 1949 | */ 1950 | 1951 | function hashSettled(object, label) { 1952 | if (!isObject(object)) { 1953 | return Promise.reject(new TypeError("RSVP.hashSettled must be called with an object"), label); 1954 | } 1955 | 1956 | return new HashSettled(Promise, object, false, label).promise; 1957 | } 1958 | 1959 | /** 1960 | `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event 1961 | loop in order to aid debugging. 1962 | 1963 | Promises A+ specifies that any exceptions that occur with a promise must be 1964 | caught by the promises implementation and bubbled to the last handler. For 1965 | this reason, it is recommended that you always specify a second rejection 1966 | handler function to `then`. However, `RSVP.rethrow` will throw the exception 1967 | outside of the promise, so it bubbles up to your console if in the browser, 1968 | or domain/cause uncaught exception in Node. `rethrow` will also throw the 1969 | error again so the error can be handled by the promise per the spec. 1970 | 1971 | ```javascript 1972 | function throws(){ 1973 | throw new Error('Whoops!'); 1974 | } 1975 | 1976 | let promise = new RSVP.Promise(function(resolve, reject){ 1977 | throws(); 1978 | }); 1979 | 1980 | promise.catch(RSVP.rethrow).then(function(){ 1981 | // Code here doesn't run because the promise became rejected due to an 1982 | // error! 1983 | }, function (err){ 1984 | // handle the error here 1985 | }); 1986 | ``` 1987 | 1988 | The 'Whoops' error will be thrown on the next turn of the event loop 1989 | and you can watch for it in your console. You can also handle it using a 1990 | rejection handler given to `.then` or `.catch` on the returned promise. 1991 | 1992 | @method rethrow 1993 | @static 1994 | @for RSVP 1995 | @param {Error} reason reason the promise became rejected. 1996 | @throws Error 1997 | @static 1998 | */ 1999 | function rethrow(reason) { 2000 | setTimeout(function () { 2001 | throw reason; 2002 | }); 2003 | throw reason; 2004 | } 2005 | 2006 | /** 2007 | `RSVP.defer` returns an object similar to jQuery's `$.Deferred`. 2008 | `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s 2009 | interface. New code should use the `RSVP.Promise` constructor instead. 2010 | 2011 | The object returned from `RSVP.defer` is a plain object with three properties: 2012 | 2013 | * promise - an `RSVP.Promise`. 2014 | * reject - a function that causes the `promise` property on this object to 2015 | become rejected 2016 | * resolve - a function that causes the `promise` property on this object to 2017 | become fulfilled. 2018 | 2019 | Example: 2020 | 2021 | ```javascript 2022 | let deferred = RSVP.defer(); 2023 | 2024 | deferred.resolve("Success!"); 2025 | 2026 | deferred.promise.then(function(value){ 2027 | // value here is "Success!" 2028 | }); 2029 | ``` 2030 | 2031 | @method defer 2032 | @static 2033 | @for RSVP 2034 | @param {String} label optional string for labeling the promise. 2035 | Useful for tooling. 2036 | @return {Object} 2037 | */ 2038 | 2039 | function defer(label) { 2040 | var deferred = { resolve: undefined, reject: undefined }; 2041 | 2042 | deferred.promise = new Promise(function (resolve, reject) { 2043 | deferred.resolve = resolve; 2044 | deferred.reject = reject; 2045 | }, label); 2046 | 2047 | return deferred; 2048 | } 2049 | 2050 | function _possibleConstructorReturn$3(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 2051 | 2052 | function _inherits$3(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 2053 | 2054 | var MapEnumerator = function (_Enumerator) { 2055 | _inherits$3(MapEnumerator, _Enumerator); 2056 | 2057 | function MapEnumerator(Constructor, entries, mapFn, label) { 2058 | return _possibleConstructorReturn$3(this, _Enumerator.call(this, Constructor, entries, true, label, mapFn)); 2059 | } 2060 | 2061 | MapEnumerator.prototype._init = function _init(Constructor, input, bool, label, mapFn) { 2062 | var len = input.length || 0; 2063 | this.length = len; 2064 | this._remaining = len; 2065 | this._result = new Array(len); 2066 | this._mapFn = mapFn; 2067 | 2068 | this._enumerate(input); 2069 | }; 2070 | 2071 | MapEnumerator.prototype._setResultAt = function _setResultAt(state, i, value, firstPass) { 2072 | if (firstPass) { 2073 | var val = tryCatch(this._mapFn)(value, i); 2074 | if (val === TRY_CATCH_ERROR) { 2075 | this._settledAt(REJECTED, i, val.error, false); 2076 | } else { 2077 | this._eachEntry(val, i, false); 2078 | } 2079 | } else { 2080 | this._remaining--; 2081 | this._result[i] = value; 2082 | } 2083 | }; 2084 | 2085 | return MapEnumerator; 2086 | }(Enumerator); 2087 | 2088 | /** 2089 | `RSVP.map` is similar to JavaScript's native `map` method. `mapFn` is eagerly called 2090 | meaning that as soon as any promise resolves its value will be passed to `mapFn`. 2091 | `RSVP.map` returns a promise that will become fulfilled with the result of running 2092 | `mapFn` on the values the promises become fulfilled with. 2093 | 2094 | For example: 2095 | 2096 | ```javascript 2097 | 2098 | let promise1 = RSVP.resolve(1); 2099 | let promise2 = RSVP.resolve(2); 2100 | let promise3 = RSVP.resolve(3); 2101 | let promises = [ promise1, promise2, promise3 ]; 2102 | 2103 | let mapFn = function(item){ 2104 | return item + 1; 2105 | }; 2106 | 2107 | RSVP.map(promises, mapFn).then(function(result){ 2108 | // result is [ 2, 3, 4 ] 2109 | }); 2110 | ``` 2111 | 2112 | If any of the `promises` given to `RSVP.map` are rejected, the first promise 2113 | that is rejected will be given as an argument to the returned promise's 2114 | rejection handler. For example: 2115 | 2116 | ```javascript 2117 | let promise1 = RSVP.resolve(1); 2118 | let promise2 = RSVP.reject(new Error('2')); 2119 | let promise3 = RSVP.reject(new Error('3')); 2120 | let promises = [ promise1, promise2, promise3 ]; 2121 | 2122 | let mapFn = function(item){ 2123 | return item + 1; 2124 | }; 2125 | 2126 | RSVP.map(promises, mapFn).then(function(array){ 2127 | // Code here never runs because there are rejected promises! 2128 | }, function(reason) { 2129 | // reason.message === '2' 2130 | }); 2131 | ``` 2132 | 2133 | `RSVP.map` will also wait if a promise is returned from `mapFn`. For example, 2134 | say you want to get all comments from a set of blog posts, but you need 2135 | the blog posts first because they contain a url to those comments. 2136 | 2137 | ```javscript 2138 | 2139 | let mapFn = function(blogPost){ 2140 | // getComments does some ajax and returns an RSVP.Promise that is fulfilled 2141 | // with some comments data 2142 | return getComments(blogPost.comments_url); 2143 | }; 2144 | 2145 | // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled 2146 | // with some blog post data 2147 | RSVP.map(getBlogPosts(), mapFn).then(function(comments){ 2148 | // comments is the result of asking the server for the comments 2149 | // of all blog posts returned from getBlogPosts() 2150 | }); 2151 | ``` 2152 | 2153 | @method map 2154 | @static 2155 | @for RSVP 2156 | @param {Array} promises 2157 | @param {Function} mapFn function to be called on each fulfilled promise. 2158 | @param {String} label optional string for labeling the promise. 2159 | Useful for tooling. 2160 | @return {Promise} promise that is fulfilled with the result of calling 2161 | `mapFn` on each fulfilled promise or value when they become fulfilled. 2162 | The promise will be rejected if any of the given `promises` become rejected. 2163 | @static 2164 | */ 2165 | 2166 | 2167 | function map(promises, mapFn, label) { 2168 | if (!Array.isArray(promises)) { 2169 | return Promise.reject(new TypeError("RSVP.map must be called with an array"), label); 2170 | } 2171 | 2172 | if (!isFunction(mapFn)) { 2173 | return Promise.reject(new TypeError("RSVP.map expects a function as a second argument"), label); 2174 | } 2175 | 2176 | return new MapEnumerator(Promise, promises, mapFn, label).promise; 2177 | } 2178 | 2179 | /** 2180 | This is a convenient alias for `RSVP.Promise.resolve`. 2181 | 2182 | @method resolve 2183 | @static 2184 | @for RSVP 2185 | @param {*} value value that the returned promise will be resolved with 2186 | @param {String} label optional string for identifying the returned promise. 2187 | Useful for tooling. 2188 | @return {Promise} a promise that will become fulfilled with the given 2189 | `value` 2190 | */ 2191 | function resolve$2(value, label) { 2192 | return Promise.resolve(value, label); 2193 | } 2194 | 2195 | /** 2196 | This is a convenient alias for `RSVP.Promise.reject`. 2197 | 2198 | @method reject 2199 | @static 2200 | @for RSVP 2201 | @param {*} reason value that the returned promise will be rejected with. 2202 | @param {String} label optional string for identifying the returned promise. 2203 | Useful for tooling. 2204 | @return {Promise} a promise rejected with the given `reason`. 2205 | */ 2206 | function reject$2(reason, label) { 2207 | return Promise.reject(reason, label); 2208 | } 2209 | 2210 | function _possibleConstructorReturn$4(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 2211 | 2212 | function _inherits$4(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 2213 | 2214 | var EMPTY_OBJECT = {}; 2215 | 2216 | var FilterEnumerator = function (_Enumerator) { 2217 | _inherits$4(FilterEnumerator, _Enumerator); 2218 | 2219 | function FilterEnumerator(Constructor, entries, filterFn, label) { 2220 | return _possibleConstructorReturn$4(this, _Enumerator.call(this, Constructor, entries, true, label, filterFn)); 2221 | } 2222 | 2223 | FilterEnumerator.prototype._init = function _init(Constructor, input, bool, label, filterFn) { 2224 | var len = input.length || 0; 2225 | this.length = len; 2226 | this._remaining = len; 2227 | 2228 | this._result = new Array(len); 2229 | this._filterFn = filterFn; 2230 | 2231 | this._enumerate(input); 2232 | }; 2233 | 2234 | FilterEnumerator.prototype._checkFullfillment = function _checkFullfillment() { 2235 | if (this._remaining === 0) { 2236 | this._result = this._result.filter(function (val) { 2237 | return val !== EMPTY_OBJECT; 2238 | }); 2239 | fulfill(this.promise, this._result); 2240 | } 2241 | }; 2242 | 2243 | FilterEnumerator.prototype._setResultAt = function _setResultAt(state, i, value, firstPass) { 2244 | if (firstPass) { 2245 | this._result[i] = value; 2246 | var val = tryCatch(this._filterFn)(value, i); 2247 | if (val === TRY_CATCH_ERROR) { 2248 | this._settledAt(REJECTED, i, val.error, false); 2249 | } else { 2250 | this._eachEntry(val, i, false); 2251 | } 2252 | } else { 2253 | this._remaining--; 2254 | if (!value) { 2255 | this._result[i] = EMPTY_OBJECT; 2256 | } 2257 | } 2258 | }; 2259 | 2260 | return FilterEnumerator; 2261 | }(Enumerator); 2262 | 2263 | /** 2264 | `RSVP.filter` is similar to JavaScript's native `filter` method. 2265 | `filterFn` is eagerly called meaning that as soon as any promise 2266 | resolves its value will be passed to `filterFn`. `RSVP.filter` returns 2267 | a promise that will become fulfilled with the result of running 2268 | `filterFn` on the values the promises become fulfilled with. 2269 | 2270 | For example: 2271 | 2272 | ```javascript 2273 | 2274 | let promise1 = RSVP.resolve(1); 2275 | let promise2 = RSVP.resolve(2); 2276 | let promise3 = RSVP.resolve(3); 2277 | 2278 | let promises = [promise1, promise2, promise3]; 2279 | 2280 | let filterFn = function(item){ 2281 | return item > 1; 2282 | }; 2283 | 2284 | RSVP.filter(promises, filterFn).then(function(result){ 2285 | // result is [ 2, 3 ] 2286 | }); 2287 | ``` 2288 | 2289 | If any of the `promises` given to `RSVP.filter` are rejected, the first promise 2290 | that is rejected will be given as an argument to the returned promise's 2291 | rejection handler. For example: 2292 | 2293 | ```javascript 2294 | let promise1 = RSVP.resolve(1); 2295 | let promise2 = RSVP.reject(new Error('2')); 2296 | let promise3 = RSVP.reject(new Error('3')); 2297 | let promises = [ promise1, promise2, promise3 ]; 2298 | 2299 | let filterFn = function(item){ 2300 | return item > 1; 2301 | }; 2302 | 2303 | RSVP.filter(promises, filterFn).then(function(array){ 2304 | // Code here never runs because there are rejected promises! 2305 | }, function(reason) { 2306 | // reason.message === '2' 2307 | }); 2308 | ``` 2309 | 2310 | `RSVP.filter` will also wait for any promises returned from `filterFn`. 2311 | For instance, you may want to fetch a list of users then return a subset 2312 | of those users based on some asynchronous operation: 2313 | 2314 | ```javascript 2315 | 2316 | let alice = { name: 'alice' }; 2317 | let bob = { name: 'bob' }; 2318 | let users = [ alice, bob ]; 2319 | 2320 | let promises = users.map(function(user){ 2321 | return RSVP.resolve(user); 2322 | }); 2323 | 2324 | let filterFn = function(user){ 2325 | // Here, Alice has permissions to create a blog post, but Bob does not. 2326 | return getPrivilegesForUser(user).then(function(privs){ 2327 | return privs.can_create_blog_post === true; 2328 | }); 2329 | }; 2330 | RSVP.filter(promises, filterFn).then(function(users){ 2331 | // true, because the server told us only Alice can create a blog post. 2332 | users.length === 1; 2333 | // false, because Alice is the only user present in `users` 2334 | users[0] === bob; 2335 | }); 2336 | ``` 2337 | 2338 | @method filter 2339 | @static 2340 | @for RSVP 2341 | @param {Array} promises 2342 | @param {Function} filterFn - function to be called on each resolved value to 2343 | filter the final results. 2344 | @param {String} label optional string describing the promise. Useful for 2345 | tooling. 2346 | @return {Promise} 2347 | */ 2348 | 2349 | function filter(promises, filterFn, label) { 2350 | if (!Array.isArray(promises) && !(isObject(promises) && promises.then !== undefined)) { 2351 | return Promise.reject(new TypeError("RSVP.filter must be called with an array or promise"), label); 2352 | } 2353 | 2354 | if (!isFunction(filterFn)) { 2355 | return Promise.reject(new TypeError("RSVP.filter expects function as a second argument"), label); 2356 | } 2357 | 2358 | return Promise.resolve(promises, label).then(function (promises) { 2359 | return new FilterEnumerator(Promise, promises, filterFn, label).promise; 2360 | }); 2361 | } 2362 | 2363 | var len = 0; 2364 | var vertxNext = void 0; 2365 | function asap(callback, arg) { 2366 | queue$1[len] = callback; 2367 | queue$1[len + 1] = arg; 2368 | len += 2; 2369 | if (len === 2) { 2370 | // If len is 1, that means that we need to schedule an async flush. 2371 | // If additional callbacks are queued before the queue is flushed, they 2372 | // will be processed by this flush that we are scheduling. 2373 | scheduleFlush$1(); 2374 | } 2375 | } 2376 | 2377 | var browserWindow = typeof window !== 'undefined' ? window : undefined; 2378 | var browserGlobal = browserWindow || {}; 2379 | var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; 2380 | var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'; 2381 | 2382 | // test for web worker but not in IE10 2383 | var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined'; 2384 | 2385 | // node 2386 | function useNextTick() { 2387 | var nextTick = process.nextTick; 2388 | // node version 0.10.x displays a deprecation warning when nextTick is used recursively 2389 | // setImmediate should be used instead instead 2390 | var version = process.versions.node.match(/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/); 2391 | if (Array.isArray(version) && version[1] === '0' && version[2] === '10') { 2392 | nextTick = setImmediate; 2393 | } 2394 | return function () { 2395 | return nextTick(flush); 2396 | }; 2397 | } 2398 | 2399 | // vertx 2400 | function useVertxTimer() { 2401 | if (typeof vertxNext !== 'undefined') { 2402 | return function () { 2403 | vertxNext(flush); 2404 | }; 2405 | } 2406 | return useSetTimeout(); 2407 | } 2408 | 2409 | function useMutationObserver() { 2410 | var iterations = 0; 2411 | var observer = new BrowserMutationObserver(flush); 2412 | var node = document.createTextNode(''); 2413 | observer.observe(node, { characterData: true }); 2414 | 2415 | return function () { 2416 | return node.data = iterations = ++iterations % 2; 2417 | }; 2418 | } 2419 | 2420 | // web worker 2421 | function useMessageChannel() { 2422 | var channel = new MessageChannel(); 2423 | channel.port1.onmessage = flush; 2424 | return function () { 2425 | return channel.port2.postMessage(0); 2426 | }; 2427 | } 2428 | 2429 | function useSetTimeout() { 2430 | return function () { 2431 | return setTimeout(flush, 1); 2432 | }; 2433 | } 2434 | 2435 | var queue$1 = new Array(1000); 2436 | 2437 | function flush() { 2438 | for (var i = 0; i < len; i += 2) { 2439 | var callback = queue$1[i]; 2440 | var arg = queue$1[i + 1]; 2441 | 2442 | callback(arg); 2443 | 2444 | queue$1[i] = undefined; 2445 | queue$1[i + 1] = undefined; 2446 | } 2447 | 2448 | len = 0; 2449 | } 2450 | 2451 | function attemptVertex() { 2452 | try { 2453 | var r = require; 2454 | var vertx = r('vertx'); 2455 | vertxNext = vertx.runOnLoop || vertx.runOnContext; 2456 | return useVertxTimer(); 2457 | } catch (e) { 2458 | return useSetTimeout(); 2459 | } 2460 | } 2461 | 2462 | var scheduleFlush$1 = void 0; 2463 | // Decide what async method to use to triggering processing of queued callbacks: 2464 | if (isNode) { 2465 | scheduleFlush$1 = useNextTick(); 2466 | } else if (BrowserMutationObserver) { 2467 | scheduleFlush$1 = useMutationObserver(); 2468 | } else if (isWorker) { 2469 | scheduleFlush$1 = useMessageChannel(); 2470 | } else if (browserWindow === undefined && typeof require === 'function') { 2471 | scheduleFlush$1 = attemptVertex(); 2472 | } else { 2473 | scheduleFlush$1 = useSetTimeout(); 2474 | } 2475 | 2476 | var platform = void 0; 2477 | 2478 | /* global self */ 2479 | if (typeof self === 'object') { 2480 | platform = self; 2481 | 2482 | /* global global */ 2483 | } else if (typeof global === 'object') { 2484 | platform = global; 2485 | } else { 2486 | throw new Error('no global: `self` or `global` found'); 2487 | } 2488 | 2489 | var _asap$cast$Promise$Ev; 2490 | 2491 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 2492 | 2493 | // defaults 2494 | config.async = asap; 2495 | config.after = function (cb) { 2496 | return setTimeout(cb, 0); 2497 | }; 2498 | var cast = resolve$2; 2499 | 2500 | var async = function (callback, arg) { 2501 | return config.async(callback, arg); 2502 | }; 2503 | 2504 | function on() { 2505 | config['on'].apply(config, arguments); 2506 | } 2507 | 2508 | function off() { 2509 | config['off'].apply(config, arguments); 2510 | } 2511 | 2512 | // Set up instrumentation through `window.__PROMISE_INTRUMENTATION__` 2513 | if (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') { 2514 | var callbacks = window['__PROMISE_INSTRUMENTATION__']; 2515 | configure('instrument', true); 2516 | for (var eventName in callbacks) { 2517 | if (callbacks.hasOwnProperty(eventName)) { 2518 | on(eventName, callbacks[eventName]); 2519 | } 2520 | } 2521 | } 2522 | 2523 | // the default export here is for backwards compat: 2524 | // https://github.com/tildeio/rsvp.js/issues/434 2525 | var rsvp = (_asap$cast$Promise$Ev = { 2526 | asap: asap, 2527 | cast: cast, 2528 | Promise: Promise, 2529 | EventTarget: EventTarget, 2530 | all: all$1, 2531 | allSettled: allSettled, 2532 | race: race$1, 2533 | hash: hash, 2534 | hashSettled: hashSettled, 2535 | rethrow: rethrow, 2536 | defer: defer, 2537 | denodeify: denodeify, 2538 | configure: configure, 2539 | on: on, 2540 | off: off, 2541 | resolve: resolve$2, 2542 | reject: reject$2, 2543 | map: map 2544 | }, _defineProperty(_asap$cast$Promise$Ev, 'async', async), _defineProperty(_asap$cast$Promise$Ev, 'filter', filter), _asap$cast$Promise$Ev); 2545 | 2546 | export { asap, cast, Promise, EventTarget, all$1 as all, allSettled, race$1 as race, hash, hashSettled, rethrow, defer, denodeify, configure, on, off, resolve$2 as resolve, reject$2 as reject, map, async, filter };export default rsvp; 2547 | 2548 | //# sourceMappingURL=rsvp.es.map 2549 | -------------------------------------------------------------------------------- /rsvp.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @overview RSVP - a tiny implementation of Promises/A+. 3 | * @copyright Copyright (c) 2016 Yehuda Katz, Tom Dale, Stefan Penner and contributors 4 | * @license Licensed under MIT license 5 | * See https://raw.githubusercontent.com/tildeio/rsvp.js/master/LICENSE 6 | * @version 4.0.1 7 | */ 8 | 9 | (function (global, factory) { 10 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : 11 | typeof define === 'function' && define.amd ? define(['exports'], factory) : 12 | (factory((global.RSVP = global.RSVP || {}))); 13 | }(this, (function (exports) { 'use strict'; 14 | 15 | function callbacksFor(object) { 16 | var callbacks = object._promiseCallbacks; 17 | 18 | if (!callbacks) { 19 | callbacks = object._promiseCallbacks = {}; 20 | } 21 | 22 | return callbacks; 23 | } 24 | 25 | /** 26 | @class RSVP.EventTarget 27 | */ 28 | var EventTarget = { 29 | 30 | /** 31 | `RSVP.EventTarget.mixin` extends an object with EventTarget methods. For 32 | Example: 33 | ```javascript 34 | let object = {}; 35 | RSVP.EventTarget.mixin(object); 36 | object.on('finished', function(event) { 37 | // handle event 38 | }); 39 | object.trigger('finished', { detail: value }); 40 | ``` 41 | `EventTarget.mixin` also works with prototypes: 42 | ```javascript 43 | let Person = function() {}; 44 | RSVP.EventTarget.mixin(Person.prototype); 45 | let yehuda = new Person(); 46 | let tom = new Person(); 47 | yehuda.on('poke', function(event) { 48 | console.log('Yehuda says OW'); 49 | }); 50 | tom.on('poke', function(event) { 51 | console.log('Tom says OW'); 52 | }); 53 | yehuda.trigger('poke'); 54 | tom.trigger('poke'); 55 | ``` 56 | @method mixin 57 | @for RSVP.EventTarget 58 | @private 59 | @param {Object} object object to extend with EventTarget methods 60 | */ 61 | mixin: function (object) { 62 | object['on'] = this['on']; 63 | object['off'] = this['off']; 64 | object['trigger'] = this['trigger']; 65 | object._promiseCallbacks = undefined; 66 | return object; 67 | }, 68 | 69 | 70 | /** 71 | Registers a callback to be executed when `eventName` is triggered 72 | ```javascript 73 | object.on('event', function(eventInfo){ 74 | // handle the event 75 | }); 76 | object.trigger('event'); 77 | ``` 78 | @method on 79 | @for RSVP.EventTarget 80 | @private 81 | @param {String} eventName name of the event to listen for 82 | @param {Function} callback function to be called when the event is triggered. 83 | */ 84 | on: function (eventName, callback) { 85 | if (typeof callback !== 'function') { 86 | throw new TypeError('Callback must be a function'); 87 | } 88 | 89 | var allCallbacks = callbacksFor(this), 90 | callbacks = void 0; 91 | 92 | callbacks = allCallbacks[eventName]; 93 | 94 | if (!callbacks) { 95 | callbacks = allCallbacks[eventName] = []; 96 | } 97 | 98 | if (callbacks.indexOf(callback)) { 99 | callbacks.push(callback); 100 | } 101 | }, 102 | 103 | 104 | /** 105 | You can use `off` to stop firing a particular callback for an event: 106 | ```javascript 107 | function doStuff() { // do stuff! } 108 | object.on('stuff', doStuff); 109 | object.trigger('stuff'); // doStuff will be called 110 | // Unregister ONLY the doStuff callback 111 | object.off('stuff', doStuff); 112 | object.trigger('stuff'); // doStuff will NOT be called 113 | ``` 114 | If you don't pass a `callback` argument to `off`, ALL callbacks for the 115 | event will not be executed when the event fires. For example: 116 | ```javascript 117 | let callback1 = function(){}; 118 | let callback2 = function(){}; 119 | object.on('stuff', callback1); 120 | object.on('stuff', callback2); 121 | object.trigger('stuff'); // callback1 and callback2 will be executed. 122 | object.off('stuff'); 123 | object.trigger('stuff'); // callback1 and callback2 will not be executed! 124 | ``` 125 | @method off 126 | @for RSVP.EventTarget 127 | @private 128 | @param {String} eventName event to stop listening to 129 | @param {Function} callback optional argument. If given, only the function 130 | given will be removed from the event's callback queue. If no `callback` 131 | argument is given, all callbacks will be removed from the event's callback 132 | queue. 133 | */ 134 | off: function (eventName, callback) { 135 | var allCallbacks = callbacksFor(this), 136 | callbacks = void 0, 137 | index = void 0; 138 | 139 | if (!callback) { 140 | allCallbacks[eventName] = []; 141 | return; 142 | } 143 | 144 | callbacks = allCallbacks[eventName]; 145 | 146 | index = callbacks.indexOf(callback); 147 | 148 | if (index !== -1) { 149 | callbacks.splice(index, 1); 150 | } 151 | }, 152 | 153 | 154 | /** 155 | Use `trigger` to fire custom events. For example: 156 | ```javascript 157 | object.on('foo', function(){ 158 | console.log('foo event happened!'); 159 | }); 160 | object.trigger('foo'); 161 | // 'foo event happened!' logged to the console 162 | ``` 163 | You can also pass a value as a second argument to `trigger` that will be 164 | passed as an argument to all event listeners for the event: 165 | ```javascript 166 | object.on('foo', function(value){ 167 | console.log(value.name); 168 | }); 169 | object.trigger('foo', { name: 'bar' }); 170 | // 'bar' logged to the console 171 | ``` 172 | @method trigger 173 | @for RSVP.EventTarget 174 | @private 175 | @param {String} eventName name of the event to be triggered 176 | @param {*} options optional value to be passed to any event handlers for 177 | the given `eventName` 178 | */ 179 | trigger: function (eventName, options, label) { 180 | var allCallbacks = callbacksFor(this), 181 | callbacks = void 0, 182 | callback = void 0; 183 | 184 | if (callbacks = allCallbacks[eventName]) { 185 | // Don't cache the callbacks.length since it may grow 186 | for (var i = 0; i < callbacks.length; i++) { 187 | callback = callbacks[i]; 188 | 189 | callback(options, label); 190 | } 191 | } 192 | } 193 | }; 194 | 195 | var config = { 196 | instrument: false 197 | }; 198 | 199 | EventTarget['mixin'](config); 200 | 201 | function configure(name, value) { 202 | if (arguments.length === 2) { 203 | config[name] = value; 204 | } else { 205 | return config[name]; 206 | } 207 | } 208 | 209 | function objectOrFunction(x) { 210 | var type = typeof x; 211 | return x !== null && (type === 'object' || type === 'function'); 212 | } 213 | 214 | function isFunction(x) { 215 | return typeof x === 'function'; 216 | } 217 | 218 | function isObject(x) { 219 | return x !== null && typeof x === 'object'; 220 | } 221 | 222 | function isMaybeThenable(x) { 223 | return x !== null && typeof x === 'object'; 224 | } 225 | 226 | var queue = []; 227 | 228 | function scheduleFlush() { 229 | setTimeout(function () { 230 | for (var i = 0; i < queue.length; i++) { 231 | var entry = queue[i]; 232 | 233 | var payload = entry.payload; 234 | 235 | payload.guid = payload.key + payload.id; 236 | payload.childGuid = payload.key + payload.childId; 237 | if (payload.error) { 238 | payload.stack = payload.error.stack; 239 | } 240 | 241 | config['trigger'](entry.name, entry.payload); 242 | } 243 | queue.length = 0; 244 | }, 50); 245 | } 246 | 247 | function instrument(eventName, promise, child) { 248 | if (1 === queue.push({ 249 | name: eventName, 250 | payload: { 251 | key: promise._guidKey, 252 | id: promise._id, 253 | eventName: eventName, 254 | detail: promise._result, 255 | childId: child && child._id, 256 | label: promise._label, 257 | timeStamp: Date.now(), 258 | error: config["instrument-with-stack"] ? new Error(promise._label) : null 259 | } })) { 260 | scheduleFlush(); 261 | } 262 | } 263 | 264 | /** 265 | `RSVP.Promise.resolve` returns a promise that will become resolved with the 266 | passed `value`. It is shorthand for the following: 267 | 268 | ```javascript 269 | let promise = new RSVP.Promise(function(resolve, reject){ 270 | resolve(1); 271 | }); 272 | 273 | promise.then(function(value){ 274 | // value === 1 275 | }); 276 | ``` 277 | 278 | Instead of writing the above, your code now simply becomes the following: 279 | 280 | ```javascript 281 | let promise = RSVP.Promise.resolve(1); 282 | 283 | promise.then(function(value){ 284 | // value === 1 285 | }); 286 | ``` 287 | 288 | @method resolve 289 | @static 290 | @param {*} object value that the returned promise will be resolved with 291 | @param {String} label optional string for identifying the returned promise. 292 | Useful for tooling. 293 | @return {Promise} a promise that will become fulfilled with the given 294 | `value` 295 | */ 296 | function resolve$1(object, label) { 297 | /*jshint validthis:true */ 298 | var Constructor = this; 299 | 300 | if (object && typeof object === 'object' && object.constructor === Constructor) { 301 | return object; 302 | } 303 | 304 | var promise = new Constructor(noop, label); 305 | resolve(promise, object); 306 | return promise; 307 | } 308 | 309 | function withOwnPromise() { 310 | return new TypeError('A promises callback cannot return that same promise.'); 311 | } 312 | 313 | function noop() {} 314 | 315 | var PENDING = void 0; 316 | var FULFILLED = 1; 317 | var REJECTED = 2; 318 | 319 | function ErrorObject() { 320 | this.error = null; 321 | } 322 | 323 | var GET_THEN_ERROR = new ErrorObject(); 324 | 325 | function getThen(promise) { 326 | try { 327 | return promise.then; 328 | } catch (error) { 329 | GET_THEN_ERROR.error = error; 330 | return GET_THEN_ERROR; 331 | } 332 | } 333 | 334 | var TRY_CATCH_ERROR = new ErrorObject(); 335 | 336 | var tryCatchCallback = void 0; 337 | function tryCatcher() { 338 | try { 339 | var target = tryCatchCallback; 340 | tryCatchCallback = null; 341 | return target.apply(this, arguments); 342 | } catch (e) { 343 | TRY_CATCH_ERROR.error = e; 344 | return TRY_CATCH_ERROR; 345 | } 346 | } 347 | 348 | function tryCatch(fn) { 349 | tryCatchCallback = fn; 350 | return tryCatcher; 351 | } 352 | 353 | function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) { 354 | try { 355 | then$$1.call(value, fulfillmentHandler, rejectionHandler); 356 | } catch (e) { 357 | return e; 358 | } 359 | } 360 | 361 | function handleForeignThenable(promise, thenable, then$$1) { 362 | config.async(function (promise) { 363 | var sealed = false; 364 | var error = tryThen(then$$1, thenable, function (value) { 365 | if (sealed) { 366 | return; 367 | } 368 | sealed = true; 369 | if (thenable !== value) { 370 | resolve(promise, value, undefined); 371 | } else { 372 | fulfill(promise, value); 373 | } 374 | }, function (reason) { 375 | if (sealed) { 376 | return; 377 | } 378 | sealed = true; 379 | 380 | reject(promise, reason); 381 | }, 'Settle: ' + (promise._label || ' unknown promise')); 382 | 383 | if (!sealed && error) { 384 | sealed = true; 385 | reject(promise, error); 386 | } 387 | }, promise); 388 | } 389 | 390 | function handleOwnThenable(promise, thenable) { 391 | if (thenable._state === FULFILLED) { 392 | fulfill(promise, thenable._result); 393 | } else if (thenable._state === REJECTED) { 394 | thenable._onError = null; 395 | reject(promise, thenable._result); 396 | } else { 397 | subscribe(thenable, undefined, function (value) { 398 | if (thenable !== value) { 399 | resolve(promise, value, undefined); 400 | } else { 401 | fulfill(promise, value); 402 | } 403 | }, function (reason) { 404 | return reject(promise, reason); 405 | }); 406 | } 407 | } 408 | 409 | function handleMaybeThenable(promise, maybeThenable, then$$1) { 410 | var isOwnThenable = maybeThenable.constructor === promise.constructor && then$$1 === then && promise.constructor.resolve === resolve$1; 411 | 412 | if (isOwnThenable) { 413 | handleOwnThenable(promise, maybeThenable); 414 | } else if (then$$1 === GET_THEN_ERROR) { 415 | reject(promise, GET_THEN_ERROR.error); 416 | GET_THEN_ERROR.error = null; 417 | } else if (isFunction(then$$1)) { 418 | handleForeignThenable(promise, maybeThenable, then$$1); 419 | } else { 420 | fulfill(promise, maybeThenable); 421 | } 422 | } 423 | 424 | function resolve(promise, value) { 425 | if (promise === value) { 426 | fulfill(promise, value); 427 | } else if (objectOrFunction(value)) { 428 | handleMaybeThenable(promise, value, getThen(value)); 429 | } else { 430 | fulfill(promise, value); 431 | } 432 | } 433 | 434 | function publishRejection(promise) { 435 | if (promise._onError) { 436 | promise._onError(promise._result); 437 | } 438 | 439 | publish(promise); 440 | } 441 | 442 | function fulfill(promise, value) { 443 | if (promise._state !== PENDING) { 444 | return; 445 | } 446 | 447 | promise._result = value; 448 | promise._state = FULFILLED; 449 | 450 | if (promise._subscribers.length === 0) { 451 | if (config.instrument) { 452 | instrument('fulfilled', promise); 453 | } 454 | } else { 455 | config.async(publish, promise); 456 | } 457 | } 458 | 459 | function reject(promise, reason) { 460 | if (promise._state !== PENDING) { 461 | return; 462 | } 463 | promise._state = REJECTED; 464 | promise._result = reason; 465 | config.async(publishRejection, promise); 466 | } 467 | 468 | function subscribe(parent, child, onFulfillment, onRejection) { 469 | var subscribers = parent._subscribers; 470 | var length = subscribers.length; 471 | 472 | parent._onError = null; 473 | 474 | subscribers[length] = child; 475 | subscribers[length + FULFILLED] = onFulfillment; 476 | subscribers[length + REJECTED] = onRejection; 477 | 478 | if (length === 0 && parent._state) { 479 | config.async(publish, parent); 480 | } 481 | } 482 | 483 | function publish(promise) { 484 | var subscribers = promise._subscribers; 485 | var settled = promise._state; 486 | 487 | if (config.instrument) { 488 | instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise); 489 | } 490 | 491 | if (subscribers.length === 0) { 492 | return; 493 | } 494 | 495 | var child = void 0, 496 | callback = void 0, 497 | result = promise._result; 498 | 499 | for (var i = 0; i < subscribers.length; i += 3) { 500 | child = subscribers[i]; 501 | callback = subscribers[i + settled]; 502 | 503 | if (child) { 504 | invokeCallback(settled, child, callback, result); 505 | } else { 506 | callback(result); 507 | } 508 | } 509 | 510 | promise._subscribers.length = 0; 511 | } 512 | 513 | function invokeCallback(state, promise, callback, result) { 514 | var hasCallback = isFunction(callback); 515 | var value = void 0, 516 | error = void 0; 517 | 518 | if (hasCallback) { 519 | value = tryCatch(callback)(result); 520 | 521 | if (value === TRY_CATCH_ERROR) { 522 | error = value.error; 523 | value.error = null; // release 524 | } else if (value === promise) { 525 | reject(promise, withOwnPromise()); 526 | return; 527 | } 528 | } else { 529 | value = result; 530 | } 531 | 532 | if (promise._state !== PENDING) { 533 | // noop 534 | } else if (hasCallback && error === undefined) { 535 | resolve(promise, value); 536 | } else if (error !== undefined) { 537 | reject(promise, error); 538 | } else if (state === FULFILLED) { 539 | fulfill(promise, value); 540 | } else if (state === REJECTED) { 541 | reject(promise, value); 542 | } 543 | } 544 | 545 | function initializePromise(promise, resolver) { 546 | var resolved = false; 547 | try { 548 | resolver(function (value) { 549 | if (resolved) { 550 | return; 551 | } 552 | resolved = true; 553 | resolve(promise, value); 554 | }, function (reason) { 555 | if (resolved) { 556 | return; 557 | } 558 | resolved = true; 559 | reject(promise, reason); 560 | }); 561 | } catch (e) { 562 | reject(promise, e); 563 | } 564 | } 565 | 566 | function then(onFulfillment, onRejection, label) { 567 | var parent = this; 568 | var state = parent._state; 569 | 570 | if (state === FULFILLED && !onFulfillment || state === REJECTED && !onRejection) { 571 | config.instrument && instrument('chained', parent, parent); 572 | return parent; 573 | } 574 | 575 | parent._onError = null; 576 | 577 | var child = new parent.constructor(noop, label); 578 | var result = parent._result; 579 | 580 | config.instrument && instrument('chained', parent, child); 581 | 582 | if (state === PENDING) { 583 | subscribe(parent, child, onFulfillment, onRejection); 584 | } else { 585 | var callback = state === FULFILLED ? onFulfillment : onRejection; 586 | config.async(function () { 587 | return invokeCallback(state, child, callback, result); 588 | }); 589 | } 590 | 591 | return child; 592 | } 593 | 594 | var Enumerator = function () { 595 | function Enumerator(Constructor, input, abortOnReject, label) { 596 | this._instanceConstructor = Constructor; 597 | this.promise = new Constructor(noop, label); 598 | this._abortOnReject = abortOnReject; 599 | this.isUsingOwnPromise = Constructor === Promise; 600 | 601 | this._init.apply(this, arguments); 602 | } 603 | 604 | Enumerator.prototype._init = function _init(Constructor, input) { 605 | var len = input.length || 0; 606 | this.length = len; 607 | this._remaining = len; 608 | this._result = new Array(len); 609 | 610 | this._enumerate(input); 611 | }; 612 | 613 | Enumerator.prototype._enumerate = function _enumerate(input) { 614 | var length = this.length; 615 | var promise = this.promise; 616 | 617 | for (var i = 0; promise._state === PENDING && i < length; i++) { 618 | this._eachEntry(input[i], i, true); 619 | } 620 | 621 | this._checkFullfillment(); 622 | }; 623 | 624 | Enumerator.prototype._checkFullfillment = function _checkFullfillment() { 625 | if (this._remaining === 0) { 626 | fulfill(this.promise, this._result); 627 | } 628 | }; 629 | 630 | Enumerator.prototype._settleMaybeThenable = function _settleMaybeThenable(entry, i, firstPass) { 631 | var c = this._instanceConstructor; 632 | var resolve$$1 = c.resolve; 633 | 634 | if (resolve$$1 === resolve$1) { 635 | var then$$1 = getThen(entry); 636 | 637 | if (then$$1 === then && entry._state !== PENDING) { 638 | entry._onError = null; 639 | this._settledAt(entry._state, i, entry._result, firstPass); 640 | } else if (typeof then$$1 !== 'function') { 641 | this._settledAt(FULFILLED, i, entry, firstPass); 642 | } else if (this.isUsingOwnPromise) { 643 | var promise = new c(noop); 644 | handleMaybeThenable(promise, entry, then$$1); 645 | this._willSettleAt(promise, i, firstPass); 646 | } else { 647 | this._willSettleAt(new c(function (resolve$$1) { 648 | return resolve$$1(entry); 649 | }), i, firstPass); 650 | } 651 | } else { 652 | this._willSettleAt(resolve$$1(entry), i, firstPass); 653 | } 654 | }; 655 | 656 | Enumerator.prototype._eachEntry = function _eachEntry(entry, i, firstPass) { 657 | if (isMaybeThenable(entry)) { 658 | this._settleMaybeThenable(entry, i, firstPass); 659 | } else { 660 | this._setResultAt(FULFILLED, i, entry, firstPass); 661 | } 662 | }; 663 | 664 | Enumerator.prototype._settledAt = function _settledAt(state, i, value, firstPass) { 665 | var promise = this.promise; 666 | 667 | if (promise._state === PENDING) { 668 | if (this._abortOnReject && state === REJECTED) { 669 | reject(promise, value); 670 | } else { 671 | this._setResultAt(state, i, value, firstPass); 672 | this._checkFullfillment(); 673 | } 674 | } 675 | }; 676 | 677 | Enumerator.prototype._setResultAt = function _setResultAt(state, i, value, firstPass) { 678 | this._remaining--; 679 | this._result[i] = value; 680 | }; 681 | 682 | Enumerator.prototype._willSettleAt = function _willSettleAt(promise, i, firstPass) { 683 | var _this = this; 684 | 685 | subscribe(promise, undefined, function (value) { 686 | return _this._settledAt(FULFILLED, i, value, firstPass); 687 | }, function (reason) { 688 | return _this._settledAt(REJECTED, i, reason, firstPass); 689 | }); 690 | }; 691 | 692 | return Enumerator; 693 | }(); 694 | 695 | function setSettledResult(state, i, value) { 696 | this._remaining--; 697 | if (state === FULFILLED) { 698 | this._result[i] = { 699 | state: 'fulfilled', 700 | value: value 701 | }; 702 | } else { 703 | this._result[i] = { 704 | state: 'rejected', 705 | reason: value 706 | }; 707 | } 708 | } 709 | 710 | /** 711 | `RSVP.Promise.all` accepts an array of promises, and returns a new promise which 712 | is fulfilled with an array of fulfillment values for the passed promises, or 713 | rejected with the reason of the first passed promise to be rejected. It casts all 714 | elements of the passed iterable to promises as it runs this algorithm. 715 | 716 | Example: 717 | 718 | ```javascript 719 | let promise1 = RSVP.resolve(1); 720 | let promise2 = RSVP.resolve(2); 721 | let promise3 = RSVP.resolve(3); 722 | let promises = [ promise1, promise2, promise3 ]; 723 | 724 | RSVP.Promise.all(promises).then(function(array){ 725 | // The array here would be [ 1, 2, 3 ]; 726 | }); 727 | ``` 728 | 729 | If any of the `promises` given to `RSVP.all` are rejected, the first promise 730 | that is rejected will be given as an argument to the returned promises's 731 | rejection handler. For example: 732 | 733 | Example: 734 | 735 | ```javascript 736 | let promise1 = RSVP.resolve(1); 737 | let promise2 = RSVP.reject(new Error("2")); 738 | let promise3 = RSVP.reject(new Error("3")); 739 | let promises = [ promise1, promise2, promise3 ]; 740 | 741 | RSVP.Promise.all(promises).then(function(array){ 742 | // Code here never runs because there are rejected promises! 743 | }, function(error) { 744 | // error.message === "2" 745 | }); 746 | ``` 747 | 748 | @method all 749 | @static 750 | @param {Array} entries array of promises 751 | @param {String} label optional string for labeling the promise. 752 | Useful for tooling. 753 | @return {Promise} promise that is fulfilled when all `promises` have been 754 | fulfilled, or rejected if any of them become rejected. 755 | @static 756 | */ 757 | function all(entries, label) { 758 | if (!Array.isArray(entries)) { 759 | return this.reject(new TypeError("Promise.all must be called with an array"), label); 760 | } 761 | return new Enumerator(this, entries, true /* abort on reject */, label).promise; 762 | } 763 | 764 | /** 765 | `RSVP.Promise.race` returns a new promise which is settled in the same way as the 766 | first passed promise to settle. 767 | 768 | Example: 769 | 770 | ```javascript 771 | let promise1 = new RSVP.Promise(function(resolve, reject){ 772 | setTimeout(function(){ 773 | resolve('promise 1'); 774 | }, 200); 775 | }); 776 | 777 | let promise2 = new RSVP.Promise(function(resolve, reject){ 778 | setTimeout(function(){ 779 | resolve('promise 2'); 780 | }, 100); 781 | }); 782 | 783 | RSVP.Promise.race([promise1, promise2]).then(function(result){ 784 | // result === 'promise 2' because it was resolved before promise1 785 | // was resolved. 786 | }); 787 | ``` 788 | 789 | `RSVP.Promise.race` is deterministic in that only the state of the first 790 | settled promise matters. For example, even if other promises given to the 791 | `promises` array argument are resolved, but the first settled promise has 792 | become rejected before the other promises became fulfilled, the returned 793 | promise will become rejected: 794 | 795 | ```javascript 796 | let promise1 = new RSVP.Promise(function(resolve, reject){ 797 | setTimeout(function(){ 798 | resolve('promise 1'); 799 | }, 200); 800 | }); 801 | 802 | let promise2 = new RSVP.Promise(function(resolve, reject){ 803 | setTimeout(function(){ 804 | reject(new Error('promise 2')); 805 | }, 100); 806 | }); 807 | 808 | RSVP.Promise.race([promise1, promise2]).then(function(result){ 809 | // Code here never runs 810 | }, function(reason){ 811 | // reason.message === 'promise 2' because promise 2 became rejected before 812 | // promise 1 became fulfilled 813 | }); 814 | ``` 815 | 816 | An example real-world use case is implementing timeouts: 817 | 818 | ```javascript 819 | RSVP.Promise.race([ajax('foo.json'), timeout(5000)]) 820 | ``` 821 | 822 | @method race 823 | @static 824 | @param {Array} entries array of promises to observe 825 | @param {String} label optional string for describing the promise returned. 826 | Useful for tooling. 827 | @return {Promise} a promise which settles in the same way as the first passed 828 | promise to settle. 829 | */ 830 | function race(entries, label) { 831 | /*jshint validthis:true */ 832 | var Constructor = this; 833 | 834 | var promise = new Constructor(noop, label); 835 | 836 | if (!Array.isArray(entries)) { 837 | reject(promise, new TypeError('Promise.race must be called with an array')); 838 | return promise; 839 | } 840 | 841 | for (var i = 0; promise._state === PENDING && i < entries.length; i++) { 842 | subscribe(Constructor.resolve(entries[i]), undefined, function (value) { 843 | return resolve(promise, value); 844 | }, function (reason) { 845 | return reject(promise, reason); 846 | }); 847 | } 848 | 849 | return promise; 850 | } 851 | 852 | /** 853 | `RSVP.Promise.reject` returns a promise rejected with the passed `reason`. 854 | It is shorthand for the following: 855 | 856 | ```javascript 857 | let promise = new RSVP.Promise(function(resolve, reject){ 858 | reject(new Error('WHOOPS')); 859 | }); 860 | 861 | promise.then(function(value){ 862 | // Code here doesn't run because the promise is rejected! 863 | }, function(reason){ 864 | // reason.message === 'WHOOPS' 865 | }); 866 | ``` 867 | 868 | Instead of writing the above, your code now simply becomes the following: 869 | 870 | ```javascript 871 | let promise = RSVP.Promise.reject(new Error('WHOOPS')); 872 | 873 | promise.then(function(value){ 874 | // Code here doesn't run because the promise is rejected! 875 | }, function(reason){ 876 | // reason.message === 'WHOOPS' 877 | }); 878 | ``` 879 | 880 | @method reject 881 | @static 882 | @param {*} reason value that the returned promise will be rejected with. 883 | @param {String} label optional string for identifying the returned promise. 884 | Useful for tooling. 885 | @return {Promise} a promise rejected with the given `reason`. 886 | */ 887 | function reject$1(reason, label) { 888 | /*jshint validthis:true */ 889 | var Constructor = this; 890 | var promise = new Constructor(noop, label); 891 | reject(promise, reason); 892 | return promise; 893 | } 894 | 895 | var guidKey = 'rsvp_' + Date.now() + '-'; 896 | var counter = 0; 897 | 898 | function needsResolver() { 899 | throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); 900 | } 901 | 902 | function needsNew() { 903 | throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); 904 | } 905 | 906 | /** 907 | Promise objects represent the eventual result of an asynchronous operation. The 908 | primary way of interacting with a promise is through its `then` method, which 909 | registers callbacks to receive either a promise’s eventual value or the reason 910 | why the promise cannot be fulfilled. 911 | 912 | Terminology 913 | ----------- 914 | 915 | - `promise` is an object or function with a `then` method whose behavior conforms to this specification. 916 | - `thenable` is an object or function that defines a `then` method. 917 | - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). 918 | - `exception` is a value that is thrown using the throw statement. 919 | - `reason` is a value that indicates why a promise was rejected. 920 | - `settled` the final resting state of a promise, fulfilled or rejected. 921 | 922 | A promise can be in one of three states: pending, fulfilled, or rejected. 923 | 924 | Promises that are fulfilled have a fulfillment value and are in the fulfilled 925 | state. Promises that are rejected have a rejection reason and are in the 926 | rejected state. A fulfillment value is never a thenable. 927 | 928 | Promises can also be said to *resolve* a value. If this value is also a 929 | promise, then the original promise's settled state will match the value's 930 | settled state. So a promise that *resolves* a promise that rejects will 931 | itself reject, and a promise that *resolves* a promise that fulfills will 932 | itself fulfill. 933 | 934 | 935 | Basic Usage: 936 | ------------ 937 | 938 | ```js 939 | let promise = new Promise(function(resolve, reject) { 940 | // on success 941 | resolve(value); 942 | 943 | // on failure 944 | reject(reason); 945 | }); 946 | 947 | promise.then(function(value) { 948 | // on fulfillment 949 | }, function(reason) { 950 | // on rejection 951 | }); 952 | ``` 953 | 954 | Advanced Usage: 955 | --------------- 956 | 957 | Promises shine when abstracting away asynchronous interactions such as 958 | `XMLHttpRequest`s. 959 | 960 | ```js 961 | function getJSON(url) { 962 | return new Promise(function(resolve, reject){ 963 | let xhr = new XMLHttpRequest(); 964 | 965 | xhr.open('GET', url); 966 | xhr.onreadystatechange = handler; 967 | xhr.responseType = 'json'; 968 | xhr.setRequestHeader('Accept', 'application/json'); 969 | xhr.send(); 970 | 971 | function handler() { 972 | if (this.readyState === this.DONE) { 973 | if (this.status === 200) { 974 | resolve(this.response); 975 | } else { 976 | reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); 977 | } 978 | } 979 | }; 980 | }); 981 | } 982 | 983 | getJSON('/posts.json').then(function(json) { 984 | // on fulfillment 985 | }, function(reason) { 986 | // on rejection 987 | }); 988 | ``` 989 | 990 | Unlike callbacks, promises are great composable primitives. 991 | 992 | ```js 993 | Promise.all([ 994 | getJSON('/posts'), 995 | getJSON('/comments') 996 | ]).then(function(values){ 997 | values[0] // => postsJSON 998 | values[1] // => commentsJSON 999 | 1000 | return values; 1001 | }); 1002 | ``` 1003 | 1004 | @class RSVP.Promise 1005 | @param {function} resolver 1006 | @param {String} label optional string for labeling the promise. 1007 | Useful for tooling. 1008 | @constructor 1009 | */ 1010 | 1011 | var Promise = function () { 1012 | function Promise(resolver, label) { 1013 | this._id = counter++; 1014 | this._label = label; 1015 | this._state = undefined; 1016 | this._result = undefined; 1017 | this._subscribers = []; 1018 | 1019 | config.instrument && instrument('created', this); 1020 | 1021 | if (noop !== resolver) { 1022 | typeof resolver !== 'function' && needsResolver(); 1023 | this instanceof Promise ? initializePromise(this, resolver) : needsNew(); 1024 | } 1025 | } 1026 | 1027 | Promise.prototype._onError = function _onError(reason) { 1028 | var _this = this; 1029 | 1030 | config.after(function () { 1031 | if (_this._onError) { 1032 | config.trigger('error', reason, _this._label); 1033 | } 1034 | }); 1035 | }; 1036 | 1037 | /** 1038 | `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same 1039 | as the catch block of a try/catch statement. 1040 | 1041 | ```js 1042 | function findAuthor(){ 1043 | throw new Error('couldn\'t find that author'); 1044 | } 1045 | 1046 | // synchronous 1047 | try { 1048 | findAuthor(); 1049 | } catch(reason) { 1050 | // something went wrong 1051 | } 1052 | 1053 | // async with promises 1054 | findAuthor().catch(function(reason){ 1055 | // something went wrong 1056 | }); 1057 | ``` 1058 | 1059 | @method catch 1060 | @param {Function} onRejection 1061 | @param {String} label optional string for labeling the promise. 1062 | Useful for tooling. 1063 | @return {Promise} 1064 | */ 1065 | 1066 | 1067 | Promise.prototype.catch = function _catch(onRejection, label) { 1068 | return this.then(undefined, onRejection, label); 1069 | }; 1070 | 1071 | /** 1072 | `finally` will be invoked regardless of the promise's fate just as native 1073 | try/catch/finally behaves 1074 | 1075 | Synchronous example: 1076 | 1077 | ```js 1078 | findAuthor() { 1079 | if (Math.random() > 0.5) { 1080 | throw new Error(); 1081 | } 1082 | return new Author(); 1083 | } 1084 | 1085 | try { 1086 | return findAuthor(); // succeed or fail 1087 | } catch(error) { 1088 | return findOtherAuthor(); 1089 | } finally { 1090 | // always runs 1091 | // doesn't affect the return value 1092 | } 1093 | ``` 1094 | 1095 | Asynchronous example: 1096 | 1097 | ```js 1098 | findAuthor().catch(function(reason){ 1099 | return findOtherAuthor(); 1100 | }).finally(function(){ 1101 | // author was either found, or not 1102 | }); 1103 | ``` 1104 | 1105 | @method finally 1106 | @param {Function} callback 1107 | @param {String} label optional string for labeling the promise. 1108 | Useful for tooling. 1109 | @return {Promise} 1110 | */ 1111 | 1112 | 1113 | Promise.prototype.finally = function _finally(callback, label) { 1114 | var promise = this; 1115 | var constructor = promise.constructor; 1116 | 1117 | return promise.then(function (value) { 1118 | return constructor.resolve(callback()).then(function () { 1119 | return value; 1120 | }); 1121 | }, function (reason) { 1122 | return constructor.resolve(callback()).then(function () { 1123 | throw reason; 1124 | }); 1125 | }, label); 1126 | }; 1127 | 1128 | return Promise; 1129 | }(); 1130 | 1131 | Promise.cast = resolve$1; // deprecated 1132 | Promise.all = all; 1133 | Promise.race = race; 1134 | Promise.resolve = resolve$1; 1135 | Promise.reject = reject$1; 1136 | 1137 | Promise.prototype._guidKey = guidKey; 1138 | 1139 | /** 1140 | The primary way of interacting with a promise is through its `then` method, 1141 | which registers callbacks to receive either a promise's eventual value or the 1142 | reason why the promise cannot be fulfilled. 1143 | 1144 | ```js 1145 | findUser().then(function(user){ 1146 | // user is available 1147 | }, function(reason){ 1148 | // user is unavailable, and you are given the reason why 1149 | }); 1150 | ``` 1151 | 1152 | Chaining 1153 | -------- 1154 | 1155 | The return value of `then` is itself a promise. This second, 'downstream' 1156 | promise is resolved with the return value of the first promise's fulfillment 1157 | or rejection handler, or rejected if the handler throws an exception. 1158 | 1159 | ```js 1160 | findUser().then(function (user) { 1161 | return user.name; 1162 | }, function (reason) { 1163 | return 'default name'; 1164 | }).then(function (userName) { 1165 | // If `findUser` fulfilled, `userName` will be the user's name, otherwise it 1166 | // will be `'default name'` 1167 | }); 1168 | 1169 | findUser().then(function (user) { 1170 | throw new Error('Found user, but still unhappy'); 1171 | }, function (reason) { 1172 | throw new Error('`findUser` rejected and we\'re unhappy'); 1173 | }).then(function (value) { 1174 | // never reached 1175 | }, function (reason) { 1176 | // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. 1177 | // If `findUser` rejected, `reason` will be '`findUser` rejected and we\'re unhappy'. 1178 | }); 1179 | ``` 1180 | If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. 1181 | 1182 | ```js 1183 | findUser().then(function (user) { 1184 | throw new PedagogicalException('Upstream error'); 1185 | }).then(function (value) { 1186 | // never reached 1187 | }).then(function (value) { 1188 | // never reached 1189 | }, function (reason) { 1190 | // The `PedgagocialException` is propagated all the way down to here 1191 | }); 1192 | ``` 1193 | 1194 | Assimilation 1195 | ------------ 1196 | 1197 | Sometimes the value you want to propagate to a downstream promise can only be 1198 | retrieved asynchronously. This can be achieved by returning a promise in the 1199 | fulfillment or rejection handler. The downstream promise will then be pending 1200 | until the returned promise is settled. This is called *assimilation*. 1201 | 1202 | ```js 1203 | findUser().then(function (user) { 1204 | return findCommentsByAuthor(user); 1205 | }).then(function (comments) { 1206 | // The user's comments are now available 1207 | }); 1208 | ``` 1209 | 1210 | If the assimliated promise rejects, then the downstream promise will also reject. 1211 | 1212 | ```js 1213 | findUser().then(function (user) { 1214 | return findCommentsByAuthor(user); 1215 | }).then(function (comments) { 1216 | // If `findCommentsByAuthor` fulfills, we'll have the value here 1217 | }, function (reason) { 1218 | // If `findCommentsByAuthor` rejects, we'll have the reason here 1219 | }); 1220 | ``` 1221 | 1222 | Simple Example 1223 | -------------- 1224 | 1225 | Synchronous Example 1226 | 1227 | ```javascript 1228 | let result; 1229 | 1230 | try { 1231 | result = findResult(); 1232 | // success 1233 | } catch(reason) { 1234 | // failure 1235 | } 1236 | ``` 1237 | 1238 | Errback Example 1239 | 1240 | ```js 1241 | findResult(function(result, err){ 1242 | if (err) { 1243 | // failure 1244 | } else { 1245 | // success 1246 | } 1247 | }); 1248 | ``` 1249 | 1250 | Promise Example; 1251 | 1252 | ```javascript 1253 | findResult().then(function(result){ 1254 | // success 1255 | }, function(reason){ 1256 | // failure 1257 | }); 1258 | ``` 1259 | 1260 | Advanced Example 1261 | -------------- 1262 | 1263 | Synchronous Example 1264 | 1265 | ```javascript 1266 | let author, books; 1267 | 1268 | try { 1269 | author = findAuthor(); 1270 | books = findBooksByAuthor(author); 1271 | // success 1272 | } catch(reason) { 1273 | // failure 1274 | } 1275 | ``` 1276 | 1277 | Errback Example 1278 | 1279 | ```js 1280 | 1281 | function foundBooks(books) { 1282 | 1283 | } 1284 | 1285 | function failure(reason) { 1286 | 1287 | } 1288 | 1289 | findAuthor(function(author, err){ 1290 | if (err) { 1291 | failure(err); 1292 | // failure 1293 | } else { 1294 | try { 1295 | findBoooksByAuthor(author, function(books, err) { 1296 | if (err) { 1297 | failure(err); 1298 | } else { 1299 | try { 1300 | foundBooks(books); 1301 | } catch(reason) { 1302 | failure(reason); 1303 | } 1304 | } 1305 | }); 1306 | } catch(error) { 1307 | failure(err); 1308 | } 1309 | // success 1310 | } 1311 | }); 1312 | ``` 1313 | 1314 | Promise Example; 1315 | 1316 | ```javascript 1317 | findAuthor(). 1318 | then(findBooksByAuthor). 1319 | then(function(books){ 1320 | // found books 1321 | }).catch(function(reason){ 1322 | // something went wrong 1323 | }); 1324 | ``` 1325 | 1326 | @method then 1327 | @param {Function} onFulfillment 1328 | @param {Function} onRejection 1329 | @param {String} label optional string for labeling the promise. 1330 | Useful for tooling. 1331 | @return {Promise} 1332 | */ 1333 | Promise.prototype.then = then; 1334 | 1335 | function Result() { 1336 | this.value = undefined; 1337 | } 1338 | 1339 | var ERROR = new Result(); 1340 | var GET_THEN_ERROR$1 = new Result(); 1341 | 1342 | function getThen$1(obj) { 1343 | try { 1344 | return obj.then; 1345 | } catch (error) { 1346 | ERROR.value = error; 1347 | return ERROR; 1348 | } 1349 | } 1350 | 1351 | function tryApply(f, s, a) { 1352 | try { 1353 | f.apply(s, a); 1354 | } catch (error) { 1355 | ERROR.value = error; 1356 | return ERROR; 1357 | } 1358 | } 1359 | 1360 | function makeObject(_, argumentNames) { 1361 | var obj = {}; 1362 | var length = _.length; 1363 | var args = new Array(length); 1364 | 1365 | for (var x = 0; x < length; x++) { 1366 | args[x] = _[x]; 1367 | } 1368 | 1369 | for (var i = 0; i < argumentNames.length; i++) { 1370 | var name = argumentNames[i]; 1371 | obj[name] = args[i + 1]; 1372 | } 1373 | 1374 | return obj; 1375 | } 1376 | 1377 | function arrayResult(_) { 1378 | var length = _.length; 1379 | var args = new Array(length - 1); 1380 | 1381 | for (var i = 1; i < length; i++) { 1382 | args[i - 1] = _[i]; 1383 | } 1384 | 1385 | return args; 1386 | } 1387 | 1388 | function wrapThenable(then, promise) { 1389 | return { 1390 | then: function (onFulFillment, onRejection) { 1391 | return then.call(promise, onFulFillment, onRejection); 1392 | } 1393 | }; 1394 | } 1395 | 1396 | /** 1397 | `RSVP.denodeify` takes a 'node-style' function and returns a function that 1398 | will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the 1399 | browser when you'd prefer to use promises over using callbacks. For example, 1400 | `denodeify` transforms the following: 1401 | 1402 | ```javascript 1403 | let fs = require('fs'); 1404 | 1405 | fs.readFile('myfile.txt', function(err, data){ 1406 | if (err) return handleError(err); 1407 | handleData(data); 1408 | }); 1409 | ``` 1410 | 1411 | into: 1412 | 1413 | ```javascript 1414 | let fs = require('fs'); 1415 | let readFile = RSVP.denodeify(fs.readFile); 1416 | 1417 | readFile('myfile.txt').then(handleData, handleError); 1418 | ``` 1419 | 1420 | If the node function has multiple success parameters, then `denodeify` 1421 | just returns the first one: 1422 | 1423 | ```javascript 1424 | let request = RSVP.denodeify(require('request')); 1425 | 1426 | request('http://example.com').then(function(res) { 1427 | // ... 1428 | }); 1429 | ``` 1430 | 1431 | However, if you need all success parameters, setting `denodeify`'s 1432 | second parameter to `true` causes it to return all success parameters 1433 | as an array: 1434 | 1435 | ```javascript 1436 | let request = RSVP.denodeify(require('request'), true); 1437 | 1438 | request('http://example.com').then(function(result) { 1439 | // result[0] -> res 1440 | // result[1] -> body 1441 | }); 1442 | ``` 1443 | 1444 | Or if you pass it an array with names it returns the parameters as a hash: 1445 | 1446 | ```javascript 1447 | let request = RSVP.denodeify(require('request'), ['res', 'body']); 1448 | 1449 | request('http://example.com').then(function(result) { 1450 | // result.res 1451 | // result.body 1452 | }); 1453 | ``` 1454 | 1455 | Sometimes you need to retain the `this`: 1456 | 1457 | ```javascript 1458 | let app = require('express')(); 1459 | let render = RSVP.denodeify(app.render.bind(app)); 1460 | ``` 1461 | 1462 | The denodified function inherits from the original function. It works in all 1463 | environments, except IE 10 and below. Consequently all properties of the original 1464 | function are available to you. However, any properties you change on the 1465 | denodeified function won't be changed on the original function. Example: 1466 | 1467 | ```javascript 1468 | let request = RSVP.denodeify(require('request')), 1469 | cookieJar = request.jar(); // <- Inheritance is used here 1470 | 1471 | request('http://example.com', {jar: cookieJar}).then(function(res) { 1472 | // cookieJar.cookies holds now the cookies returned by example.com 1473 | }); 1474 | ``` 1475 | 1476 | Using `denodeify` makes it easier to compose asynchronous operations instead 1477 | of using callbacks. For example, instead of: 1478 | 1479 | ```javascript 1480 | let fs = require('fs'); 1481 | 1482 | fs.readFile('myfile.txt', function(err, data){ 1483 | if (err) { ... } // Handle error 1484 | fs.writeFile('myfile2.txt', data, function(err){ 1485 | if (err) { ... } // Handle error 1486 | console.log('done') 1487 | }); 1488 | }); 1489 | ``` 1490 | 1491 | you can chain the operations together using `then` from the returned promise: 1492 | 1493 | ```javascript 1494 | let fs = require('fs'); 1495 | let readFile = RSVP.denodeify(fs.readFile); 1496 | let writeFile = RSVP.denodeify(fs.writeFile); 1497 | 1498 | readFile('myfile.txt').then(function(data){ 1499 | return writeFile('myfile2.txt', data); 1500 | }).then(function(){ 1501 | console.log('done') 1502 | }).catch(function(error){ 1503 | // Handle error 1504 | }); 1505 | ``` 1506 | 1507 | @method denodeify 1508 | @static 1509 | @for RSVP 1510 | @param {Function} nodeFunc a 'node-style' function that takes a callback as 1511 | its last argument. The callback expects an error to be passed as its first 1512 | argument (if an error occurred, otherwise null), and the value from the 1513 | operation as its second argument ('function(err, value){ }'). 1514 | @param {Boolean|Array} [options] An optional paramter that if set 1515 | to `true` causes the promise to fulfill with the callback's success arguments 1516 | as an array. This is useful if the node function has multiple success 1517 | paramters. If you set this paramter to an array with names, the promise will 1518 | fulfill with a hash with these names as keys and the success parameters as 1519 | values. 1520 | @return {Function} a function that wraps `nodeFunc` to return an 1521 | `RSVP.Promise` 1522 | @static 1523 | */ 1524 | function denodeify(nodeFunc, options) { 1525 | var fn = function () { 1526 | var self = this; 1527 | var l = arguments.length; 1528 | var args = new Array(l + 1); 1529 | var promiseInput = false; 1530 | 1531 | for (var i = 0; i < l; ++i) { 1532 | var arg = arguments[i]; 1533 | 1534 | if (!promiseInput) { 1535 | // TODO: clean this up 1536 | promiseInput = needsPromiseInput(arg); 1537 | if (promiseInput === GET_THEN_ERROR$1) { 1538 | var p = new Promise(noop); 1539 | reject(p, GET_THEN_ERROR$1.value); 1540 | return p; 1541 | } else if (promiseInput && promiseInput !== true) { 1542 | arg = wrapThenable(promiseInput, arg); 1543 | } 1544 | } 1545 | args[i] = arg; 1546 | } 1547 | 1548 | var promise = new Promise(noop); 1549 | 1550 | args[l] = function (err, val) { 1551 | if (err) reject(promise, err);else if (options === undefined) resolve(promise, val);else if (options === true) resolve(promise, arrayResult(arguments));else if (Array.isArray(options)) resolve(promise, makeObject(arguments, options));else resolve(promise, val); 1552 | }; 1553 | 1554 | if (promiseInput) { 1555 | return handlePromiseInput(promise, args, nodeFunc, self); 1556 | } else { 1557 | return handleValueInput(promise, args, nodeFunc, self); 1558 | } 1559 | }; 1560 | 1561 | fn.__proto__ = nodeFunc; 1562 | 1563 | return fn; 1564 | } 1565 | 1566 | function handleValueInput(promise, args, nodeFunc, self) { 1567 | var result = tryApply(nodeFunc, self, args); 1568 | if (result === ERROR) { 1569 | reject(promise, result.value); 1570 | } 1571 | return promise; 1572 | } 1573 | 1574 | function handlePromiseInput(promise, args, nodeFunc, self) { 1575 | return Promise.all(args).then(function (args) { 1576 | var result = tryApply(nodeFunc, self, args); 1577 | if (result === ERROR) { 1578 | reject(promise, result.value); 1579 | } 1580 | return promise; 1581 | }); 1582 | } 1583 | 1584 | function needsPromiseInput(arg) { 1585 | if (arg && typeof arg === 'object') { 1586 | if (arg.constructor === Promise) { 1587 | return true; 1588 | } else { 1589 | return getThen$1(arg); 1590 | } 1591 | } else { 1592 | return false; 1593 | } 1594 | } 1595 | 1596 | /** 1597 | This is a convenient alias for `RSVP.Promise.all`. 1598 | 1599 | @method all 1600 | @static 1601 | @for RSVP 1602 | @param {Array} array Array of promises. 1603 | @param {String} label An optional label. This is useful 1604 | for tooling. 1605 | */ 1606 | function all$1(array, label) { 1607 | return Promise.all(array, label); 1608 | } 1609 | 1610 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 1611 | 1612 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 1613 | 1614 | var AllSettled = function (_Enumerator) { 1615 | _inherits(AllSettled, _Enumerator); 1616 | 1617 | function AllSettled(Constructor, entries, label) { 1618 | return _possibleConstructorReturn(this, _Enumerator.call(this, Constructor, entries, false /* don't abort on reject */, label)); 1619 | } 1620 | 1621 | return AllSettled; 1622 | }(Enumerator); 1623 | 1624 | AllSettled.prototype._setResultAt = setSettledResult; 1625 | 1626 | /** 1627 | `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing 1628 | a fail-fast method, it waits until all the promises have returned and 1629 | shows you all the results. This is useful if you want to handle multiple 1630 | promises' failure states together as a set. 1631 | Returns a promise that is fulfilled when all the given promises have been 1632 | settled. The return promise is fulfilled with an array of the states of 1633 | the promises passed into the `promises` array argument. 1634 | Each state object will either indicate fulfillment or rejection, and 1635 | provide the corresponding value or reason. The states will take one of 1636 | the following formats: 1637 | ```javascript 1638 | { state: 'fulfilled', value: value } 1639 | or 1640 | { state: 'rejected', reason: reason } 1641 | ``` 1642 | Example: 1643 | ```javascript 1644 | let promise1 = RSVP.Promise.resolve(1); 1645 | let promise2 = RSVP.Promise.reject(new Error('2')); 1646 | let promise3 = RSVP.Promise.reject(new Error('3')); 1647 | let promises = [ promise1, promise2, promise3 ]; 1648 | RSVP.allSettled(promises).then(function(array){ 1649 | // array == [ 1650 | // { state: 'fulfilled', value: 1 }, 1651 | // { state: 'rejected', reason: Error }, 1652 | // { state: 'rejected', reason: Error } 1653 | // ] 1654 | // Note that for the second item, reason.message will be '2', and for the 1655 | // third item, reason.message will be '3'. 1656 | }, function(error) { 1657 | // Not run. (This block would only be called if allSettled had failed, 1658 | // for instance if passed an incorrect argument type.) 1659 | }); 1660 | ``` 1661 | @method allSettled 1662 | @static 1663 | @for RSVP 1664 | @param {Array} entries 1665 | @param {String} label - optional string that describes the promise. 1666 | Useful for tooling. 1667 | @return {Promise} promise that is fulfilled with an array of the settled 1668 | states of the constituent promises. 1669 | */ 1670 | 1671 | function allSettled(entries, label) { 1672 | if (!Array.isArray(entries)) { 1673 | return Promise.reject(new TypeError("Promise.allSettled must be called with an array"), label); 1674 | } 1675 | 1676 | return new AllSettled(Promise, entries, label).promise; 1677 | } 1678 | 1679 | /** 1680 | This is a convenient alias for `RSVP.Promise.race`. 1681 | 1682 | @method race 1683 | @static 1684 | @for RSVP 1685 | @param {Array} array Array of promises. 1686 | @param {String} label An optional label. This is useful 1687 | for tooling. 1688 | */ 1689 | function race$1(array, label) { 1690 | return Promise.race(array, label); 1691 | } 1692 | 1693 | function _possibleConstructorReturn$1(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 1694 | 1695 | function _inherits$1(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 1696 | 1697 | var hasOwnProperty = Object.prototype.hasOwnProperty; 1698 | 1699 | var PromiseHash = function (_Enumerator) { 1700 | _inherits$1(PromiseHash, _Enumerator); 1701 | 1702 | function PromiseHash(Constructor, object) { 1703 | var abortOnReject = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; 1704 | var label = arguments[3]; 1705 | return _possibleConstructorReturn$1(this, _Enumerator.call(this, Constructor, object, abortOnReject, label)); 1706 | } 1707 | 1708 | PromiseHash.prototype._init = function _init(Constructor, object) { 1709 | this._result = {}; 1710 | 1711 | this._enumerate(object); 1712 | if (this._remaining === 0) { 1713 | fulfill(this.promise, this._result); 1714 | } 1715 | }; 1716 | 1717 | PromiseHash.prototype._enumerate = function _enumerate(input) { 1718 | var promise = this.promise; 1719 | var results = []; 1720 | 1721 | for (var key in input) { 1722 | if (hasOwnProperty.call(input, key)) { 1723 | results.push({ 1724 | position: key, 1725 | entry: input[key] 1726 | }); 1727 | } 1728 | } 1729 | 1730 | var length = results.length; 1731 | this._remaining = length; 1732 | var result = void 0; 1733 | 1734 | for (var i = 0; promise._state === PENDING && i < length; i++) { 1735 | result = results[i]; 1736 | this._eachEntry(result.entry, result.position); 1737 | } 1738 | }; 1739 | 1740 | return PromiseHash; 1741 | }(Enumerator); 1742 | 1743 | /** 1744 | `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array 1745 | for its `promises` argument. 1746 | 1747 | Returns a promise that is fulfilled when all the given promises have been 1748 | fulfilled, or rejected if any of them become rejected. The returned promise 1749 | is fulfilled with a hash that has the same key names as the `promises` object 1750 | argument. If any of the values in the object are not promises, they will 1751 | simply be copied over to the fulfilled object. 1752 | 1753 | Example: 1754 | 1755 | ```javascript 1756 | let promises = { 1757 | myPromise: RSVP.resolve(1), 1758 | yourPromise: RSVP.resolve(2), 1759 | theirPromise: RSVP.resolve(3), 1760 | notAPromise: 4 1761 | }; 1762 | 1763 | RSVP.hash(promises).then(function(hash){ 1764 | // hash here is an object that looks like: 1765 | // { 1766 | // myPromise: 1, 1767 | // yourPromise: 2, 1768 | // theirPromise: 3, 1769 | // notAPromise: 4 1770 | // } 1771 | }); 1772 | ```` 1773 | 1774 | If any of the `promises` given to `RSVP.hash` are rejected, the first promise 1775 | that is rejected will be given as the reason to the rejection handler. 1776 | 1777 | Example: 1778 | 1779 | ```javascript 1780 | let promises = { 1781 | myPromise: RSVP.resolve(1), 1782 | rejectedPromise: RSVP.reject(new Error('rejectedPromise')), 1783 | anotherRejectedPromise: RSVP.reject(new Error('anotherRejectedPromise')), 1784 | }; 1785 | 1786 | RSVP.hash(promises).then(function(hash){ 1787 | // Code here never runs because there are rejected promises! 1788 | }, function(reason) { 1789 | // reason.message === 'rejectedPromise' 1790 | }); 1791 | ``` 1792 | 1793 | An important note: `RSVP.hash` is intended for plain JavaScript objects that 1794 | are just a set of keys and values. `RSVP.hash` will NOT preserve prototype 1795 | chains. 1796 | 1797 | Example: 1798 | 1799 | ```javascript 1800 | function MyConstructor(){ 1801 | this.example = RSVP.resolve('Example'); 1802 | } 1803 | 1804 | MyConstructor.prototype = { 1805 | protoProperty: RSVP.resolve('Proto Property') 1806 | }; 1807 | 1808 | let myObject = new MyConstructor(); 1809 | 1810 | RSVP.hash(myObject).then(function(hash){ 1811 | // protoProperty will not be present, instead you will just have an 1812 | // object that looks like: 1813 | // { 1814 | // example: 'Example' 1815 | // } 1816 | // 1817 | // hash.hasOwnProperty('protoProperty'); // false 1818 | // 'undefined' === typeof hash.protoProperty 1819 | }); 1820 | ``` 1821 | 1822 | @method hash 1823 | @static 1824 | @for RSVP 1825 | @param {Object} object 1826 | @param {String} label optional string that describes the promise. 1827 | Useful for tooling. 1828 | @return {Promise} promise that is fulfilled when all properties of `promises` 1829 | have been fulfilled, or rejected if any of them become rejected. 1830 | */ 1831 | function hash(object, label) { 1832 | if (!isObject(object)) { 1833 | return Promise.reject(new TypeError("Promise.hash must be called with an object"), label); 1834 | } 1835 | 1836 | return new PromiseHash(Promise, object, label).promise; 1837 | } 1838 | 1839 | function _possibleConstructorReturn$2(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 1840 | 1841 | function _inherits$2(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 1842 | 1843 | var HashSettled = function (_PromiseHash) { 1844 | _inherits$2(HashSettled, _PromiseHash); 1845 | 1846 | function HashSettled(Constructor, object, label) { 1847 | return _possibleConstructorReturn$2(this, _PromiseHash.call(this, Constructor, object, false, label)); 1848 | } 1849 | 1850 | return HashSettled; 1851 | }(PromiseHash); 1852 | 1853 | HashSettled.prototype._setResultAt = setSettledResult; 1854 | 1855 | /** 1856 | `RSVP.hashSettled` is similar to `RSVP.allSettled`, but takes an object 1857 | instead of an array for its `promises` argument. 1858 | 1859 | Unlike `RSVP.all` or `RSVP.hash`, which implement a fail-fast method, 1860 | but like `RSVP.allSettled`, `hashSettled` waits until all the 1861 | constituent promises have returned and then shows you all the results 1862 | with their states and values/reasons. This is useful if you want to 1863 | handle multiple promises' failure states together as a set. 1864 | 1865 | Returns a promise that is fulfilled when all the given promises have been 1866 | settled, or rejected if the passed parameters are invalid. 1867 | 1868 | The returned promise is fulfilled with a hash that has the same key names as 1869 | the `promises` object argument. If any of the values in the object are not 1870 | promises, they will be copied over to the fulfilled object and marked with state 1871 | 'fulfilled'. 1872 | 1873 | Example: 1874 | 1875 | ```javascript 1876 | let promises = { 1877 | myPromise: RSVP.Promise.resolve(1), 1878 | yourPromise: RSVP.Promise.resolve(2), 1879 | theirPromise: RSVP.Promise.resolve(3), 1880 | notAPromise: 4 1881 | }; 1882 | 1883 | RSVP.hashSettled(promises).then(function(hash){ 1884 | // hash here is an object that looks like: 1885 | // { 1886 | // myPromise: { state: 'fulfilled', value: 1 }, 1887 | // yourPromise: { state: 'fulfilled', value: 2 }, 1888 | // theirPromise: { state: 'fulfilled', value: 3 }, 1889 | // notAPromise: { state: 'fulfilled', value: 4 } 1890 | // } 1891 | }); 1892 | ``` 1893 | 1894 | If any of the `promises` given to `RSVP.hash` are rejected, the state will 1895 | be set to 'rejected' and the reason for rejection provided. 1896 | 1897 | Example: 1898 | 1899 | ```javascript 1900 | let promises = { 1901 | myPromise: RSVP.Promise.resolve(1), 1902 | rejectedPromise: RSVP.Promise.reject(new Error('rejection')), 1903 | anotherRejectedPromise: RSVP.Promise.reject(new Error('more rejection')), 1904 | }; 1905 | 1906 | RSVP.hashSettled(promises).then(function(hash){ 1907 | // hash here is an object that looks like: 1908 | // { 1909 | // myPromise: { state: 'fulfilled', value: 1 }, 1910 | // rejectedPromise: { state: 'rejected', reason: Error }, 1911 | // anotherRejectedPromise: { state: 'rejected', reason: Error }, 1912 | // } 1913 | // Note that for rejectedPromise, reason.message == 'rejection', 1914 | // and for anotherRejectedPromise, reason.message == 'more rejection'. 1915 | }); 1916 | ``` 1917 | 1918 | An important note: `RSVP.hashSettled` is intended for plain JavaScript objects that 1919 | are just a set of keys and values. `RSVP.hashSettled` will NOT preserve prototype 1920 | chains. 1921 | 1922 | Example: 1923 | 1924 | ```javascript 1925 | function MyConstructor(){ 1926 | this.example = RSVP.Promise.resolve('Example'); 1927 | } 1928 | 1929 | MyConstructor.prototype = { 1930 | protoProperty: RSVP.Promise.resolve('Proto Property') 1931 | }; 1932 | 1933 | let myObject = new MyConstructor(); 1934 | 1935 | RSVP.hashSettled(myObject).then(function(hash){ 1936 | // protoProperty will not be present, instead you will just have an 1937 | // object that looks like: 1938 | // { 1939 | // example: { state: 'fulfilled', value: 'Example' } 1940 | // } 1941 | // 1942 | // hash.hasOwnProperty('protoProperty'); // false 1943 | // 'undefined' === typeof hash.protoProperty 1944 | }); 1945 | ``` 1946 | 1947 | @method hashSettled 1948 | @for RSVP 1949 | @param {Object} object 1950 | @param {String} label optional string that describes the promise. 1951 | Useful for tooling. 1952 | @return {Promise} promise that is fulfilled when when all properties of `promises` 1953 | have been settled. 1954 | @static 1955 | */ 1956 | 1957 | function hashSettled(object, label) { 1958 | if (!isObject(object)) { 1959 | return Promise.reject(new TypeError("RSVP.hashSettled must be called with an object"), label); 1960 | } 1961 | 1962 | return new HashSettled(Promise, object, false, label).promise; 1963 | } 1964 | 1965 | /** 1966 | `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event 1967 | loop in order to aid debugging. 1968 | 1969 | Promises A+ specifies that any exceptions that occur with a promise must be 1970 | caught by the promises implementation and bubbled to the last handler. For 1971 | this reason, it is recommended that you always specify a second rejection 1972 | handler function to `then`. However, `RSVP.rethrow` will throw the exception 1973 | outside of the promise, so it bubbles up to your console if in the browser, 1974 | or domain/cause uncaught exception in Node. `rethrow` will also throw the 1975 | error again so the error can be handled by the promise per the spec. 1976 | 1977 | ```javascript 1978 | function throws(){ 1979 | throw new Error('Whoops!'); 1980 | } 1981 | 1982 | let promise = new RSVP.Promise(function(resolve, reject){ 1983 | throws(); 1984 | }); 1985 | 1986 | promise.catch(RSVP.rethrow).then(function(){ 1987 | // Code here doesn't run because the promise became rejected due to an 1988 | // error! 1989 | }, function (err){ 1990 | // handle the error here 1991 | }); 1992 | ``` 1993 | 1994 | The 'Whoops' error will be thrown on the next turn of the event loop 1995 | and you can watch for it in your console. You can also handle it using a 1996 | rejection handler given to `.then` or `.catch` on the returned promise. 1997 | 1998 | @method rethrow 1999 | @static 2000 | @for RSVP 2001 | @param {Error} reason reason the promise became rejected. 2002 | @throws Error 2003 | @static 2004 | */ 2005 | function rethrow(reason) { 2006 | setTimeout(function () { 2007 | throw reason; 2008 | }); 2009 | throw reason; 2010 | } 2011 | 2012 | /** 2013 | `RSVP.defer` returns an object similar to jQuery's `$.Deferred`. 2014 | `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s 2015 | interface. New code should use the `RSVP.Promise` constructor instead. 2016 | 2017 | The object returned from `RSVP.defer` is a plain object with three properties: 2018 | 2019 | * promise - an `RSVP.Promise`. 2020 | * reject - a function that causes the `promise` property on this object to 2021 | become rejected 2022 | * resolve - a function that causes the `promise` property on this object to 2023 | become fulfilled. 2024 | 2025 | Example: 2026 | 2027 | ```javascript 2028 | let deferred = RSVP.defer(); 2029 | 2030 | deferred.resolve("Success!"); 2031 | 2032 | deferred.promise.then(function(value){ 2033 | // value here is "Success!" 2034 | }); 2035 | ``` 2036 | 2037 | @method defer 2038 | @static 2039 | @for RSVP 2040 | @param {String} label optional string for labeling the promise. 2041 | Useful for tooling. 2042 | @return {Object} 2043 | */ 2044 | 2045 | function defer(label) { 2046 | var deferred = { resolve: undefined, reject: undefined }; 2047 | 2048 | deferred.promise = new Promise(function (resolve, reject) { 2049 | deferred.resolve = resolve; 2050 | deferred.reject = reject; 2051 | }, label); 2052 | 2053 | return deferred; 2054 | } 2055 | 2056 | function _possibleConstructorReturn$3(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 2057 | 2058 | function _inherits$3(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 2059 | 2060 | var MapEnumerator = function (_Enumerator) { 2061 | _inherits$3(MapEnumerator, _Enumerator); 2062 | 2063 | function MapEnumerator(Constructor, entries, mapFn, label) { 2064 | return _possibleConstructorReturn$3(this, _Enumerator.call(this, Constructor, entries, true, label, mapFn)); 2065 | } 2066 | 2067 | MapEnumerator.prototype._init = function _init(Constructor, input, bool, label, mapFn) { 2068 | var len = input.length || 0; 2069 | this.length = len; 2070 | this._remaining = len; 2071 | this._result = new Array(len); 2072 | this._mapFn = mapFn; 2073 | 2074 | this._enumerate(input); 2075 | }; 2076 | 2077 | MapEnumerator.prototype._setResultAt = function _setResultAt(state, i, value, firstPass) { 2078 | if (firstPass) { 2079 | var val = tryCatch(this._mapFn)(value, i); 2080 | if (val === TRY_CATCH_ERROR) { 2081 | this._settledAt(REJECTED, i, val.error, false); 2082 | } else { 2083 | this._eachEntry(val, i, false); 2084 | } 2085 | } else { 2086 | this._remaining--; 2087 | this._result[i] = value; 2088 | } 2089 | }; 2090 | 2091 | return MapEnumerator; 2092 | }(Enumerator); 2093 | 2094 | /** 2095 | `RSVP.map` is similar to JavaScript's native `map` method. `mapFn` is eagerly called 2096 | meaning that as soon as any promise resolves its value will be passed to `mapFn`. 2097 | `RSVP.map` returns a promise that will become fulfilled with the result of running 2098 | `mapFn` on the values the promises become fulfilled with. 2099 | 2100 | For example: 2101 | 2102 | ```javascript 2103 | 2104 | let promise1 = RSVP.resolve(1); 2105 | let promise2 = RSVP.resolve(2); 2106 | let promise3 = RSVP.resolve(3); 2107 | let promises = [ promise1, promise2, promise3 ]; 2108 | 2109 | let mapFn = function(item){ 2110 | return item + 1; 2111 | }; 2112 | 2113 | RSVP.map(promises, mapFn).then(function(result){ 2114 | // result is [ 2, 3, 4 ] 2115 | }); 2116 | ``` 2117 | 2118 | If any of the `promises` given to `RSVP.map` are rejected, the first promise 2119 | that is rejected will be given as an argument to the returned promise's 2120 | rejection handler. For example: 2121 | 2122 | ```javascript 2123 | let promise1 = RSVP.resolve(1); 2124 | let promise2 = RSVP.reject(new Error('2')); 2125 | let promise3 = RSVP.reject(new Error('3')); 2126 | let promises = [ promise1, promise2, promise3 ]; 2127 | 2128 | let mapFn = function(item){ 2129 | return item + 1; 2130 | }; 2131 | 2132 | RSVP.map(promises, mapFn).then(function(array){ 2133 | // Code here never runs because there are rejected promises! 2134 | }, function(reason) { 2135 | // reason.message === '2' 2136 | }); 2137 | ``` 2138 | 2139 | `RSVP.map` will also wait if a promise is returned from `mapFn`. For example, 2140 | say you want to get all comments from a set of blog posts, but you need 2141 | the blog posts first because they contain a url to those comments. 2142 | 2143 | ```javscript 2144 | 2145 | let mapFn = function(blogPost){ 2146 | // getComments does some ajax and returns an RSVP.Promise that is fulfilled 2147 | // with some comments data 2148 | return getComments(blogPost.comments_url); 2149 | }; 2150 | 2151 | // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled 2152 | // with some blog post data 2153 | RSVP.map(getBlogPosts(), mapFn).then(function(comments){ 2154 | // comments is the result of asking the server for the comments 2155 | // of all blog posts returned from getBlogPosts() 2156 | }); 2157 | ``` 2158 | 2159 | @method map 2160 | @static 2161 | @for RSVP 2162 | @param {Array} promises 2163 | @param {Function} mapFn function to be called on each fulfilled promise. 2164 | @param {String} label optional string for labeling the promise. 2165 | Useful for tooling. 2166 | @return {Promise} promise that is fulfilled with the result of calling 2167 | `mapFn` on each fulfilled promise or value when they become fulfilled. 2168 | The promise will be rejected if any of the given `promises` become rejected. 2169 | @static 2170 | */ 2171 | 2172 | 2173 | function map(promises, mapFn, label) { 2174 | if (!Array.isArray(promises)) { 2175 | return Promise.reject(new TypeError("RSVP.map must be called with an array"), label); 2176 | } 2177 | 2178 | if (!isFunction(mapFn)) { 2179 | return Promise.reject(new TypeError("RSVP.map expects a function as a second argument"), label); 2180 | } 2181 | 2182 | return new MapEnumerator(Promise, promises, mapFn, label).promise; 2183 | } 2184 | 2185 | /** 2186 | This is a convenient alias for `RSVP.Promise.resolve`. 2187 | 2188 | @method resolve 2189 | @static 2190 | @for RSVP 2191 | @param {*} value value that the returned promise will be resolved with 2192 | @param {String} label optional string for identifying the returned promise. 2193 | Useful for tooling. 2194 | @return {Promise} a promise that will become fulfilled with the given 2195 | `value` 2196 | */ 2197 | function resolve$2(value, label) { 2198 | return Promise.resolve(value, label); 2199 | } 2200 | 2201 | /** 2202 | This is a convenient alias for `RSVP.Promise.reject`. 2203 | 2204 | @method reject 2205 | @static 2206 | @for RSVP 2207 | @param {*} reason value that the returned promise will be rejected with. 2208 | @param {String} label optional string for identifying the returned promise. 2209 | Useful for tooling. 2210 | @return {Promise} a promise rejected with the given `reason`. 2211 | */ 2212 | function reject$2(reason, label) { 2213 | return Promise.reject(reason, label); 2214 | } 2215 | 2216 | function _possibleConstructorReturn$4(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 2217 | 2218 | function _inherits$4(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 2219 | 2220 | var EMPTY_OBJECT = {}; 2221 | 2222 | var FilterEnumerator = function (_Enumerator) { 2223 | _inherits$4(FilterEnumerator, _Enumerator); 2224 | 2225 | function FilterEnumerator(Constructor, entries, filterFn, label) { 2226 | return _possibleConstructorReturn$4(this, _Enumerator.call(this, Constructor, entries, true, label, filterFn)); 2227 | } 2228 | 2229 | FilterEnumerator.prototype._init = function _init(Constructor, input, bool, label, filterFn) { 2230 | var len = input.length || 0; 2231 | this.length = len; 2232 | this._remaining = len; 2233 | 2234 | this._result = new Array(len); 2235 | this._filterFn = filterFn; 2236 | 2237 | this._enumerate(input); 2238 | }; 2239 | 2240 | FilterEnumerator.prototype._checkFullfillment = function _checkFullfillment() { 2241 | if (this._remaining === 0) { 2242 | this._result = this._result.filter(function (val) { 2243 | return val !== EMPTY_OBJECT; 2244 | }); 2245 | fulfill(this.promise, this._result); 2246 | } 2247 | }; 2248 | 2249 | FilterEnumerator.prototype._setResultAt = function _setResultAt(state, i, value, firstPass) { 2250 | if (firstPass) { 2251 | this._result[i] = value; 2252 | var val = tryCatch(this._filterFn)(value, i); 2253 | if (val === TRY_CATCH_ERROR) { 2254 | this._settledAt(REJECTED, i, val.error, false); 2255 | } else { 2256 | this._eachEntry(val, i, false); 2257 | } 2258 | } else { 2259 | this._remaining--; 2260 | if (!value) { 2261 | this._result[i] = EMPTY_OBJECT; 2262 | } 2263 | } 2264 | }; 2265 | 2266 | return FilterEnumerator; 2267 | }(Enumerator); 2268 | 2269 | /** 2270 | `RSVP.filter` is similar to JavaScript's native `filter` method. 2271 | `filterFn` is eagerly called meaning that as soon as any promise 2272 | resolves its value will be passed to `filterFn`. `RSVP.filter` returns 2273 | a promise that will become fulfilled with the result of running 2274 | `filterFn` on the values the promises become fulfilled with. 2275 | 2276 | For example: 2277 | 2278 | ```javascript 2279 | 2280 | let promise1 = RSVP.resolve(1); 2281 | let promise2 = RSVP.resolve(2); 2282 | let promise3 = RSVP.resolve(3); 2283 | 2284 | let promises = [promise1, promise2, promise3]; 2285 | 2286 | let filterFn = function(item){ 2287 | return item > 1; 2288 | }; 2289 | 2290 | RSVP.filter(promises, filterFn).then(function(result){ 2291 | // result is [ 2, 3 ] 2292 | }); 2293 | ``` 2294 | 2295 | If any of the `promises` given to `RSVP.filter` are rejected, the first promise 2296 | that is rejected will be given as an argument to the returned promise's 2297 | rejection handler. For example: 2298 | 2299 | ```javascript 2300 | let promise1 = RSVP.resolve(1); 2301 | let promise2 = RSVP.reject(new Error('2')); 2302 | let promise3 = RSVP.reject(new Error('3')); 2303 | let promises = [ promise1, promise2, promise3 ]; 2304 | 2305 | let filterFn = function(item){ 2306 | return item > 1; 2307 | }; 2308 | 2309 | RSVP.filter(promises, filterFn).then(function(array){ 2310 | // Code here never runs because there are rejected promises! 2311 | }, function(reason) { 2312 | // reason.message === '2' 2313 | }); 2314 | ``` 2315 | 2316 | `RSVP.filter` will also wait for any promises returned from `filterFn`. 2317 | For instance, you may want to fetch a list of users then return a subset 2318 | of those users based on some asynchronous operation: 2319 | 2320 | ```javascript 2321 | 2322 | let alice = { name: 'alice' }; 2323 | let bob = { name: 'bob' }; 2324 | let users = [ alice, bob ]; 2325 | 2326 | let promises = users.map(function(user){ 2327 | return RSVP.resolve(user); 2328 | }); 2329 | 2330 | let filterFn = function(user){ 2331 | // Here, Alice has permissions to create a blog post, but Bob does not. 2332 | return getPrivilegesForUser(user).then(function(privs){ 2333 | return privs.can_create_blog_post === true; 2334 | }); 2335 | }; 2336 | RSVP.filter(promises, filterFn).then(function(users){ 2337 | // true, because the server told us only Alice can create a blog post. 2338 | users.length === 1; 2339 | // false, because Alice is the only user present in `users` 2340 | users[0] === bob; 2341 | }); 2342 | ``` 2343 | 2344 | @method filter 2345 | @static 2346 | @for RSVP 2347 | @param {Array} promises 2348 | @param {Function} filterFn - function to be called on each resolved value to 2349 | filter the final results. 2350 | @param {String} label optional string describing the promise. Useful for 2351 | tooling. 2352 | @return {Promise} 2353 | */ 2354 | 2355 | function filter(promises, filterFn, label) { 2356 | if (!Array.isArray(promises) && !(isObject(promises) && promises.then !== undefined)) { 2357 | return Promise.reject(new TypeError("RSVP.filter must be called with an array or promise"), label); 2358 | } 2359 | 2360 | if (!isFunction(filterFn)) { 2361 | return Promise.reject(new TypeError("RSVP.filter expects function as a second argument"), label); 2362 | } 2363 | 2364 | return Promise.resolve(promises, label).then(function (promises) { 2365 | return new FilterEnumerator(Promise, promises, filterFn, label).promise; 2366 | }); 2367 | } 2368 | 2369 | var len = 0; 2370 | var vertxNext = void 0; 2371 | function asap(callback, arg) { 2372 | queue$1[len] = callback; 2373 | queue$1[len + 1] = arg; 2374 | len += 2; 2375 | if (len === 2) { 2376 | // If len is 1, that means that we need to schedule an async flush. 2377 | // If additional callbacks are queued before the queue is flushed, they 2378 | // will be processed by this flush that we are scheduling. 2379 | scheduleFlush$1(); 2380 | } 2381 | } 2382 | 2383 | var browserWindow = typeof window !== 'undefined' ? window : undefined; 2384 | var browserGlobal = browserWindow || {}; 2385 | var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; 2386 | var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'; 2387 | 2388 | // test for web worker but not in IE10 2389 | var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined'; 2390 | 2391 | // node 2392 | function useNextTick() { 2393 | var nextTick = process.nextTick; 2394 | // node version 0.10.x displays a deprecation warning when nextTick is used recursively 2395 | // setImmediate should be used instead instead 2396 | var version = process.versions.node.match(/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/); 2397 | if (Array.isArray(version) && version[1] === '0' && version[2] === '10') { 2398 | nextTick = setImmediate; 2399 | } 2400 | return function () { 2401 | return nextTick(flush); 2402 | }; 2403 | } 2404 | 2405 | // vertx 2406 | function useVertxTimer() { 2407 | if (typeof vertxNext !== 'undefined') { 2408 | return function () { 2409 | vertxNext(flush); 2410 | }; 2411 | } 2412 | return useSetTimeout(); 2413 | } 2414 | 2415 | function useMutationObserver() { 2416 | var iterations = 0; 2417 | var observer = new BrowserMutationObserver(flush); 2418 | var node = document.createTextNode(''); 2419 | observer.observe(node, { characterData: true }); 2420 | 2421 | return function () { 2422 | return node.data = iterations = ++iterations % 2; 2423 | }; 2424 | } 2425 | 2426 | // web worker 2427 | function useMessageChannel() { 2428 | var channel = new MessageChannel(); 2429 | channel.port1.onmessage = flush; 2430 | return function () { 2431 | return channel.port2.postMessage(0); 2432 | }; 2433 | } 2434 | 2435 | function useSetTimeout() { 2436 | return function () { 2437 | return setTimeout(flush, 1); 2438 | }; 2439 | } 2440 | 2441 | var queue$1 = new Array(1000); 2442 | 2443 | function flush() { 2444 | for (var i = 0; i < len; i += 2) { 2445 | var callback = queue$1[i]; 2446 | var arg = queue$1[i + 1]; 2447 | 2448 | callback(arg); 2449 | 2450 | queue$1[i] = undefined; 2451 | queue$1[i + 1] = undefined; 2452 | } 2453 | 2454 | len = 0; 2455 | } 2456 | 2457 | function attemptVertex() { 2458 | try { 2459 | var r = require; 2460 | var vertx = r('vertx'); 2461 | vertxNext = vertx.runOnLoop || vertx.runOnContext; 2462 | return useVertxTimer(); 2463 | } catch (e) { 2464 | return useSetTimeout(); 2465 | } 2466 | } 2467 | 2468 | var scheduleFlush$1 = void 0; 2469 | // Decide what async method to use to triggering processing of queued callbacks: 2470 | if (isNode) { 2471 | scheduleFlush$1 = useNextTick(); 2472 | } else if (BrowserMutationObserver) { 2473 | scheduleFlush$1 = useMutationObserver(); 2474 | } else if (isWorker) { 2475 | scheduleFlush$1 = useMessageChannel(); 2476 | } else if (browserWindow === undefined && typeof require === 'function') { 2477 | scheduleFlush$1 = attemptVertex(); 2478 | } else { 2479 | scheduleFlush$1 = useSetTimeout(); 2480 | } 2481 | 2482 | var platform = void 0; 2483 | 2484 | /* global self */ 2485 | if (typeof self === 'object') { 2486 | platform = self; 2487 | 2488 | /* global global */ 2489 | } else if (typeof global === 'object') { 2490 | platform = global; 2491 | } else { 2492 | throw new Error('no global: `self` or `global` found'); 2493 | } 2494 | 2495 | var _asap$cast$Promise$Ev; 2496 | 2497 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 2498 | 2499 | // defaults 2500 | config.async = asap; 2501 | config.after = function (cb) { 2502 | return setTimeout(cb, 0); 2503 | }; 2504 | var cast = resolve$2; 2505 | 2506 | var async = function (callback, arg) { 2507 | return config.async(callback, arg); 2508 | }; 2509 | 2510 | function on() { 2511 | config['on'].apply(config, arguments); 2512 | } 2513 | 2514 | function off() { 2515 | config['off'].apply(config, arguments); 2516 | } 2517 | 2518 | // Set up instrumentation through `window.__PROMISE_INTRUMENTATION__` 2519 | if (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') { 2520 | var callbacks = window['__PROMISE_INSTRUMENTATION__']; 2521 | configure('instrument', true); 2522 | for (var eventName in callbacks) { 2523 | if (callbacks.hasOwnProperty(eventName)) { 2524 | on(eventName, callbacks[eventName]); 2525 | } 2526 | } 2527 | } 2528 | 2529 | // the default export here is for backwards compat: 2530 | // https://github.com/tildeio/rsvp.js/issues/434 2531 | var rsvp = (_asap$cast$Promise$Ev = { 2532 | asap: asap, 2533 | cast: cast, 2534 | Promise: Promise, 2535 | EventTarget: EventTarget, 2536 | all: all$1, 2537 | allSettled: allSettled, 2538 | race: race$1, 2539 | hash: hash, 2540 | hashSettled: hashSettled, 2541 | rethrow: rethrow, 2542 | defer: defer, 2543 | denodeify: denodeify, 2544 | configure: configure, 2545 | on: on, 2546 | off: off, 2547 | resolve: resolve$2, 2548 | reject: reject$2, 2549 | map: map 2550 | }, _defineProperty(_asap$cast$Promise$Ev, 'async', async), _defineProperty(_asap$cast$Promise$Ev, 'filter', filter), _asap$cast$Promise$Ev); 2551 | 2552 | exports['default'] = rsvp; 2553 | exports.asap = asap; 2554 | exports.cast = cast; 2555 | exports.Promise = Promise; 2556 | exports.EventTarget = EventTarget; 2557 | exports.all = all$1; 2558 | exports.allSettled = allSettled; 2559 | exports.race = race$1; 2560 | exports.hash = hash; 2561 | exports.hashSettled = hashSettled; 2562 | exports.rethrow = rethrow; 2563 | exports.defer = defer; 2564 | exports.denodeify = denodeify; 2565 | exports.configure = configure; 2566 | exports.on = on; 2567 | exports.off = off; 2568 | exports.resolve = resolve$2; 2569 | exports.reject = reject$2; 2570 | exports.map = map; 2571 | exports.async = async; 2572 | exports.filter = filter; 2573 | 2574 | Object.defineProperty(exports, '__esModule', { value: true }); 2575 | 2576 | }))); 2577 | 2578 | //# sourceMappingURL=rsvp.map 2579 | --------------------------------------------------------------------------------