Переглянути джерело

core: Move waiting for multiple `addFile()` promises into a util class.

Renée Kooi 7 роки тому
батько
коміт
940678e103
3 змінених файлів з 82 додано та 27 видалено
  1. 4 27
      src/core/Core.js
  2. 37 0
      src/core/Core.test.js
  3. 41 0
      src/core/PromiseWaiter.js

+ 4 - 27
src/core/Core.js

@@ -1,5 +1,6 @@
 const Utils = require('../core/Utils')
 const Translator = require('../core/Translator')
+const PromiseWaiter = require('./PromiseWaiter')
 const ee = require('namespace-emitter')
 const cuid = require('cuid')
 const throttle = require('lodash.throttle')
@@ -120,7 +121,7 @@ class Uppy {
       this.updateAll(nextState)
     })
 
-    this.addFilePromises = []
+    this.addFilePromises = new PromiseWaiter()
 
     // for debugging and testing
     // this.updateNum = 0
@@ -407,35 +408,11 @@ class Uppy {
         return Promise.reject(typeof err === 'object' ? err : new Error(err))
       })
 
-    this.addFilePromises.push(promise)
-    const removePromise = () => {
-      const i = this.addFilePromises.indexOf(promise)
-      if (i !== -1) {
-        this.addFilePromises.splice(i, 1)
-      }
-    }
-    promise.then(removePromise, removePromise)
+    this.addFilePromises.add(promise)
 
     return promise
   }
 
-  waitForAddFilePromises () {
-    const promises = this.addFilePromises
-    this.addFilePromises = []
-
-    function noop () {
-      // No result value
-    }
-
-    return Promise.all(promises.map(concluded)).then(noop)
-
-    // Just wait for a Promise to conclude in some way, whether it's resolution
-    // or rejection. We don't care about the contents.
-    function concluded (promise) {
-      return promise.then(noop, noop)
-    }
-  }
-
   removeFile (fileID) {
     const { files, currentUploads } = this.state
     const updatedFiles = Object.assign({}, files)
@@ -1143,7 +1120,7 @@ class Uppy {
       this.log('No uploader type plugins are used', 'warning')
     }
 
-    return this.waitForAddFilePromises()
+    return this.addFilePromises.wait()
       .then(() => this.opts.onBeforeUpload(this.getState().files))
       .then(() => this._checkMinNumberOfFiles())
       .then(() => {

+ 37 - 0
src/core/Core.test.js

@@ -710,6 +710,43 @@ describe('src/Core', () => {
         expect(result).toMatchSnapshot()
       })
     })
+
+    it('should wait for addFile() promises to resolve before starting the upload', () => {
+      const resolves = []
+      const onBeforeUpload = jest.fn(() => {
+        expect(resolves.length).toBe(0)
+        return Promise.resolve()
+      })
+      const uppy = new Core({
+        autoProceed: false,
+        onBeforeFileAdded () {
+          // Queue `addFile` promises to be resolved _after_
+          // calling `upload()`.
+          return new Promise((resolve) => {
+            resolves.push(resolve)
+          })
+        },
+        onBeforeUpload
+      })
+
+      uppy.addFile({ name: 'a', data: Buffer.from('a') })
+      uppy.addFile({ name: 'b', data: Buffer.from('b') })
+
+      return Promise.resolve().then(() => {
+        expect(resolves.length).toBe(2)
+
+        const promise = uppy.upload()
+
+        let resolve
+        while ((resolve = resolves.pop())) {
+          resolve()
+        }
+
+        return promise
+      }).then(() => {
+        expect(onBeforeUpload).toHaveBeenCalled()
+      })
+    })
   })
 
   describe('removing a file', () => {

+ 41 - 0
src/core/PromiseWaiter.js

@@ -0,0 +1,41 @@
+/**
+ * Wait for multiple Promises to resolve.
+ */
+module.exports = class PromiseWaiter {
+  constructor () {
+    this.promises = []
+  }
+
+  add (promise) {
+    this.promises.push(promise)
+
+    const remove = () => {
+      this.remove(promise)
+    }
+    promise.then(remove, remove)
+  }
+
+  remove (promise) {
+    const index = this.promises.indexOf(promise)
+    if (index !== -1) {
+      this.promises.splice(index, 1)
+    }
+  }
+
+  wait () {
+    const promises = this.promises
+    this.promises = []
+
+    function noop () {
+      // No result value
+    }
+
+    // Just wait for a Promise to conclude in some way, whether it's resolution
+    // or rejection. We don't care about the contents.
+    function concluded (promise) {
+      return promise.then(noop, noop)
+    }
+
+    return Promise.all(promises.map(concluded)).then(noop)
+  }
+}