租房小程序前端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
4.1 KiB

3 months ago
  1. const { isArray } = require('./utils/isArray');
  2. const proto = exports;
  3. proto._parallelNode = async function _parallelNode(todo, parallel, fn, sourceData) {
  4. const that = this;
  5. // upload in parallel
  6. const jobErr = [];
  7. let jobs = [];
  8. const tempBatch = todo.length / parallel;
  9. const remainder = todo.length % parallel;
  10. const batch = remainder === 0 ? tempBatch : (todo.length - remainder) / parallel + 1;
  11. let taskIndex = 1;
  12. for (let i = 0; i < todo.length; i++) {
  13. if (that.isCancel()) {
  14. break;
  15. }
  16. if (sourceData) {
  17. jobs.push(fn(that, todo[i], sourceData));
  18. } else {
  19. jobs.push(fn(that, todo[i]));
  20. }
  21. if (jobs.length === parallel || (taskIndex === batch && i === todo.length - 1)) {
  22. try {
  23. taskIndex += 1;
  24. /* eslint no-await-in-loop: [0] */
  25. await Promise.all(jobs);
  26. } catch (err) {
  27. jobErr.push(err);
  28. }
  29. jobs = [];
  30. }
  31. }
  32. return jobErr;
  33. };
  34. proto._parallel = function _parallel(todo, parallel, jobPromise) {
  35. const that = this;
  36. return new Promise(resolve => {
  37. const _jobErr = [];
  38. if (parallel <= 0 || !todo) {
  39. resolve(_jobErr);
  40. return;
  41. }
  42. function onlyOnce(fn) {
  43. return function (...args) {
  44. if (fn === null) throw new Error('Callback was already called.');
  45. const callFn = fn;
  46. fn = null;
  47. callFn.apply(this, args);
  48. };
  49. }
  50. function createArrayIterator(coll) {
  51. let i = -1;
  52. const len = coll.length;
  53. return function next() {
  54. return ++i < len && !that.isCancel() ? { value: coll[i], key: i } : null;
  55. };
  56. }
  57. const nextElem = createArrayIterator(todo);
  58. let done = false;
  59. let running = 0;
  60. let looping = false;
  61. function iterateeCallback(err) {
  62. running -= 1;
  63. if (err) {
  64. done = true;
  65. _jobErr.push(err);
  66. resolve(_jobErr);
  67. } else if (done && running <= 0) {
  68. done = true;
  69. resolve(_jobErr);
  70. } else if (!looping) {
  71. /* eslint no-use-before-define: [0] */
  72. if (that.isCancel()) {
  73. resolve(_jobErr);
  74. } else {
  75. replenish();
  76. }
  77. }
  78. }
  79. function iteratee(value, callback) {
  80. jobPromise(value)
  81. .then(result => {
  82. callback(null, result);
  83. })
  84. .catch(err => {
  85. callback(err);
  86. });
  87. }
  88. function replenish() {
  89. looping = true;
  90. while (running < parallel && !done && !that.isCancel()) {
  91. const elem = nextElem();
  92. if (elem === null || _jobErr.length > 0) {
  93. done = true;
  94. if (running <= 0) {
  95. resolve(_jobErr);
  96. }
  97. return;
  98. }
  99. running += 1;
  100. iteratee(elem.value, onlyOnce(iterateeCallback));
  101. }
  102. looping = false;
  103. }
  104. replenish();
  105. });
  106. };
  107. /**
  108. * cancel operation, now can use with multipartUpload
  109. * @param {Object} abort
  110. * {String} anort.name object key
  111. * {String} anort.uploadId upload id
  112. * {String} anort.options timeout
  113. */
  114. proto.cancel = function cancel(abort) {
  115. this.options.cancelFlag = true;
  116. if (isArray(this.multipartUploadStreams)) {
  117. this.multipartUploadStreams.forEach(_ => {
  118. if (_.destroyed === false) {
  119. const err = {
  120. name: 'cancel',
  121. message: 'cancel'
  122. };
  123. _.destroy(err);
  124. }
  125. });
  126. }
  127. this.multipartUploadStreams = [];
  128. if (abort) {
  129. this.abortMultipartUpload(abort.name, abort.uploadId, abort.options);
  130. }
  131. };
  132. proto.isCancel = function isCancel() {
  133. return this.options.cancelFlag;
  134. };
  135. proto.resetCancelFlag = function resetCancelFlag() {
  136. this.options.cancelFlag = false;
  137. };
  138. proto._stop = function _stop() {
  139. this.options.cancelFlag = true;
  140. };
  141. // cancel is not error , so create an object
  142. proto._makeCancelEvent = function _makeCancelEvent() {
  143. const cancelEvent = {
  144. status: 0,
  145. name: 'cancel'
  146. };
  147. return cancelEvent;
  148. };
  149. // abort is not error , so create an object
  150. proto._makeAbortEvent = function _makeAbortEvent() {
  151. const abortEvent = {
  152. status: 0,
  153. name: 'abort',
  154. message: 'upload task has been abort'
  155. };
  156. return abortEvent;
  157. };