createPersistoid.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. "use strict";
  2. exports.__esModule = true;
  3. exports.default = createPersistoid;
  4. var _constants = require("./constants");
  5. // @TODO remove once flow < 0.63 support is no longer required.
  6. function createPersistoid(config) {
  7. // defaults
  8. var blacklist = config.blacklist || null;
  9. var whitelist = config.whitelist || null;
  10. var transforms = config.transforms || [];
  11. var throttle = config.throttle || 0;
  12. var storageKey = "".concat(config.keyPrefix !== undefined ? config.keyPrefix : _constants.KEY_PREFIX).concat(config.key);
  13. var storage = config.storage;
  14. var serialize;
  15. if (config.serialize === false) {
  16. serialize = function serialize(x) {
  17. return x;
  18. };
  19. } else if (typeof config.serialize === 'function') {
  20. serialize = config.serialize;
  21. } else {
  22. serialize = defaultSerialize;
  23. }
  24. var writeFailHandler = config.writeFailHandler || null; // initialize stateful values
  25. var lastState = {};
  26. var stagedState = {};
  27. var keysToProcess = [];
  28. var timeIterator = null;
  29. var writePromise = null;
  30. var update = function update(state) {
  31. // add any changed keys to the queue
  32. Object.keys(state).forEach(function (key) {
  33. if (!passWhitelistBlacklist(key)) return; // is keyspace ignored? noop
  34. if (lastState[key] === state[key]) return; // value unchanged? noop
  35. if (keysToProcess.indexOf(key) !== -1) return; // is key already queued? noop
  36. keysToProcess.push(key); // add key to queue
  37. }); //if any key is missing in the new state which was present in the lastState,
  38. //add it for processing too
  39. Object.keys(lastState).forEach(function (key) {
  40. if (state[key] === undefined && passWhitelistBlacklist(key) && keysToProcess.indexOf(key) === -1 && lastState[key] !== undefined) {
  41. keysToProcess.push(key);
  42. }
  43. }); // start the time iterator if not running (read: throttle)
  44. if (timeIterator === null) {
  45. timeIterator = setInterval(processNextKey, throttle);
  46. }
  47. lastState = state;
  48. };
  49. function processNextKey() {
  50. if (keysToProcess.length === 0) {
  51. if (timeIterator) clearInterval(timeIterator);
  52. timeIterator = null;
  53. return;
  54. }
  55. var key = keysToProcess.shift();
  56. var endState = transforms.reduce(function (subState, transformer) {
  57. return transformer.in(subState, key, lastState);
  58. }, lastState[key]);
  59. if (endState !== undefined) {
  60. try {
  61. stagedState[key] = serialize(endState);
  62. } catch (err) {
  63. console.error('redux-persist/createPersistoid: error serializing state', err);
  64. }
  65. } else {
  66. //if the endState is undefined, no need to persist the existing serialized content
  67. delete stagedState[key];
  68. }
  69. if (keysToProcess.length === 0) {
  70. writeStagedState();
  71. }
  72. }
  73. function writeStagedState() {
  74. // cleanup any removed keys just before write.
  75. Object.keys(stagedState).forEach(function (key) {
  76. if (lastState[key] === undefined) {
  77. delete stagedState[key];
  78. }
  79. });
  80. writePromise = storage.setItem(storageKey, serialize(stagedState)).catch(onWriteFail);
  81. }
  82. function passWhitelistBlacklist(key) {
  83. if (whitelist && whitelist.indexOf(key) === -1 && key !== '_persist') return false;
  84. if (blacklist && blacklist.indexOf(key) !== -1) return false;
  85. return true;
  86. }
  87. function onWriteFail(err) {
  88. // @TODO add fail handlers (typically storage full)
  89. if (writeFailHandler) writeFailHandler(err);
  90. if (err && process.env.NODE_ENV !== 'production') {
  91. console.error('Error storing data', err);
  92. }
  93. }
  94. var flush = function flush() {
  95. while (keysToProcess.length !== 0) {
  96. processNextKey();
  97. }
  98. return writePromise || Promise.resolve();
  99. }; // return `persistoid`
  100. return {
  101. update: update,
  102. flush: flush
  103. };
  104. } // @NOTE in the future this may be exposed via config
  105. function defaultSerialize(data) {
  106. return JSON.stringify(data);
  107. }