wait-service.js 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. /**
  6. * A middleware which acts like a service, because it is stateful
  7. * and "long-running" in the background. It provides the ability
  8. * for actions to install a function to be run once when a specific
  9. * condition is met by an action coming through the system. Think of
  10. * it as a thunk that blocks until the condition is met. Example:
  11. *
  12. * ```js
  13. * const services = { WAIT_UNTIL: require('wait-service').NAME };
  14. *
  15. * { type: services.WAIT_UNTIL,
  16. * predicate: action => action.type === constants.ADD_ITEM,
  17. * run: (dispatch, getState, action) => {
  18. * // Do anything here. You only need to accept the arguments
  19. * // if you need them. `action` is the action that satisfied
  20. * // the predicate.
  21. * }
  22. * }
  23. * ```
  24. */
  25. const NAME = exports.NAME = "@@service/waitUntil";
  26. function waitUntilService({ dispatch, getState }) {
  27. let pending = [];
  28. function checkPending(action) {
  29. let readyRequests = [];
  30. let stillPending = [];
  31. // Find the pending requests whose predicates are satisfied with
  32. // this action. Wait to run the requests until after we update the
  33. // pending queue because the request handler may synchronously
  34. // dispatch again and run this service (that use case is
  35. // completely valid).
  36. for (let request of pending) {
  37. if (request.predicate(action)) {
  38. readyRequests.push(request);
  39. } else {
  40. stillPending.push(request);
  41. }
  42. }
  43. pending = stillPending;
  44. for (let request of readyRequests) {
  45. request.run(dispatch, getState, action);
  46. }
  47. }
  48. return next => action => {
  49. if (action.type === NAME) {
  50. pending.push(action);
  51. return null;
  52. }
  53. let result = next(action);
  54. checkPending(action);
  55. return result;
  56. };
  57. }
  58. exports.waitUntilService = waitUntilService;