async.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. var asyncSymbol = Symbol('asyncSymbol');
  2. var deferConfig = require('./defer').deferConfig;
  3. /**
  4. * @param promiseOrFunc the promise will determine a property's value once resolved
  5. * can also be a function to defer which resolves to a promise
  6. * @returns {Promise} a marked promise to be resolve later using `resolveAsyncConfigs`
  7. */
  8. function asyncConfig(promiseOrFunc) {
  9. if (typeof promiseOrFunc === 'function') { // also acts as deferConfig
  10. return deferConfig(function (config, original) {
  11. var release;
  12. function registerRelease(resolve) { release = resolve; }
  13. function callFunc() { return promiseOrFunc.call(config, config, original); }
  14. var promise = asyncConfig(new Promise(registerRelease).then(callFunc));
  15. promise.release = release;
  16. return promise;
  17. });
  18. }
  19. var promise = promiseOrFunc;
  20. promise.async = asyncSymbol;
  21. promise.prepare = function(config, prop, property) {
  22. if (promise.release) {
  23. promise.release();
  24. }
  25. return function() {
  26. return promise.then(function(value) {
  27. Object.defineProperty(prop, property, {value: value});
  28. });
  29. };
  30. };
  31. return promise;
  32. }
  33. /**
  34. * Do not use `config.get` before executing this method, it will freeze the config object
  35. * @param config the main config object, returned from require('config')
  36. * @returns {Promise<config>} once all promises are resolved, return the original config object
  37. */
  38. function resolveAsyncConfigs(config) {
  39. var promises = [];
  40. var resolvers = [];
  41. (function iterate(prop) {
  42. var propsToSort = [];
  43. for (var property in prop) {
  44. if (Object.hasOwnProperty.call(prop, property) && prop[property] != null) {
  45. propsToSort.push(property);
  46. }
  47. }
  48. propsToSort.sort().forEach(function(property) {
  49. if (prop[property].constructor === Object) {
  50. iterate(prop[property]);
  51. }
  52. else if (prop[property].constructor === Array) {
  53. prop[property].forEach(iterate);
  54. }
  55. else if (prop[property] && prop[property].async === asyncSymbol) {
  56. resolvers.push(prop[property].prepare(config, prop, property));
  57. promises.push(prop[property]);
  58. }
  59. });
  60. })(config);
  61. return Promise.all(promises).then(function() {
  62. resolvers.forEach(function(resolve) { resolve(); });
  63. return config;
  64. });
  65. }
  66. module.exports.asyncConfig = asyncConfig;
  67. module.exports.resolveAsyncConfigs = resolveAsyncConfigs;