workqueue.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // Copyright 2015 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.async.WorkItem');
  15. goog.provide('goog.async.WorkQueue');
  16. goog.require('goog.asserts');
  17. goog.require('goog.async.FreeList');
  18. // TODO(johnlenz): generalize the WorkQueue if this is used by more
  19. // than goog.async.run.
  20. /**
  21. * A low GC workqueue. The key elements of this design:
  22. * - avoids the need for goog.bind or equivalent by carrying scope
  23. * - avoids the need for array reallocation by using a linked list
  24. * - minimizes work entry objects allocation by recycling objects
  25. * @constructor
  26. * @final
  27. * @struct
  28. */
  29. goog.async.WorkQueue = function() {
  30. this.workHead_ = null;
  31. this.workTail_ = null;
  32. };
  33. /** @define {number} The maximum number of entries to keep for recycling. */
  34. goog.define('goog.async.WorkQueue.DEFAULT_MAX_UNUSED', 100);
  35. /** @const @private {goog.async.FreeList<goog.async.WorkItem>} */
  36. goog.async.WorkQueue.freelist_ = new goog.async.FreeList(
  37. function() { return new goog.async.WorkItem(); },
  38. function(item) { item.reset(); }, goog.async.WorkQueue.DEFAULT_MAX_UNUSED);
  39. /**
  40. * @param {function()} fn
  41. * @param {Object|null|undefined} scope
  42. */
  43. goog.async.WorkQueue.prototype.add = function(fn, scope) {
  44. var item = this.getUnusedItem_();
  45. item.set(fn, scope);
  46. if (this.workTail_) {
  47. this.workTail_.next = item;
  48. this.workTail_ = item;
  49. } else {
  50. goog.asserts.assert(!this.workHead_);
  51. this.workHead_ = item;
  52. this.workTail_ = item;
  53. }
  54. };
  55. /**
  56. * @return {goog.async.WorkItem}
  57. */
  58. goog.async.WorkQueue.prototype.remove = function() {
  59. var item = null;
  60. if (this.workHead_) {
  61. item = this.workHead_;
  62. this.workHead_ = this.workHead_.next;
  63. if (!this.workHead_) {
  64. this.workTail_ = null;
  65. }
  66. item.next = null;
  67. }
  68. return item;
  69. };
  70. /**
  71. * @param {goog.async.WorkItem} item
  72. */
  73. goog.async.WorkQueue.prototype.returnUnused = function(item) {
  74. goog.async.WorkQueue.freelist_.put(item);
  75. };
  76. /**
  77. * @return {goog.async.WorkItem}
  78. * @private
  79. */
  80. goog.async.WorkQueue.prototype.getUnusedItem_ = function() {
  81. return goog.async.WorkQueue.freelist_.get();
  82. };
  83. /**
  84. * @constructor
  85. * @final
  86. * @struct
  87. */
  88. goog.async.WorkItem = function() {
  89. /** @type {?function()} */
  90. this.fn = null;
  91. /** @type {Object|null|undefined} */
  92. this.scope = null;
  93. /** @type {?goog.async.WorkItem} */
  94. this.next = null;
  95. };
  96. /**
  97. * @param {function()} fn
  98. * @param {Object|null|undefined} scope
  99. */
  100. goog.async.WorkItem.prototype.set = function(fn, scope) {
  101. this.fn = fn;
  102. this.scope = scope;
  103. this.next = null;
  104. };
  105. /** Reset the work item so they don't prevent GC before reuse */
  106. goog.async.WorkItem.prototype.reset = function() {
  107. this.fn = null;
  108. this.scope = null;
  109. this.next = null;
  110. };