You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Convert codebase to asynchronous code (reroll v2) (#363)
* Remove the synchronous functions and convert upload() and uploadNextChunk() (and upper-level resume(), pause(), cancel(), removeFile(), and retry()) to async
* Remove the need to call readFinished() from the `readFileFn` (only returns the data)
* Make FlowFile async-first and use a couple of Jasmine expectAsync()
* Maintain event flow consistency
* tests: Convert tests into async/await
* tests: added a test about async file-added hook
* doc: Adapt documentation
Co-authored-by: ilessiivi <[email protected]>
Co-authored-by: Raphaël Droz <[email protected]>
Copy file name to clipboardExpand all lines: README.md
+17-33
Original file line number
Diff line number
Diff line change
@@ -126,7 +126,7 @@ function, it will be passed a FlowFile, a FlowChunk and isTest boolean (Default:
126
126
*`testChunks` Make a GET request to the server for each chunks to see if it already exists. If implemented on the server-side, this will allow for upload resumes even after a browser crash or even a computer restart. (Default: `true`)
127
127
*`preprocess` Optional function to process each chunk before testing & sending. To the function it will be passed the chunk as parameter, and should call the `preprocessFinished` method on the chunk when finished. (Default: `null`)
128
128
*`changeRawDataBeforeSend` Optional function to change Raw Data just before the XHR Request can be sent for each chunk. To the function, it will be passed the chunk and the data as a Parameter. Return the data which will be then sent to the XHR request without further modification. (Default: `null`). This is helpful when using FlowJS with [Google Cloud Storage](https://cloud.google.com/storage/docs/json_api/v1/how-tos/multipart-upload). Usage example can be seen [#276](https://github.com/flowjs/flow.js/pull/276). (For more, check issue [#170](https://github.com/flowjs/flow.js/issues/170)).
129
-
*`initFileFn` Optional function to initialize the fileObject. To the function it will be passed a FlowFile and a FlowChunk arguments.
129
+
*`initFileFn` Optional (asynchronous) function to initialize the fileObject. To the function it will be passed a FlowFile and a FlowChunk arguments.
130
130
*`readFileFn` Optional function wrapping reading operation from the original file. To the function it will be passed the FlowFile, the startByte and endByte, the fileType and the FlowChunk.
131
131
*`generateUniqueIdentifier` Override the function that generates unique identifiers for each file. (Default: `null`)
132
132
*`maxChunkRetries` The maximum number of retries for a chunk before the upload is failed. Valid values are any positive integer and `undefined` for no limit. (Default: `0`)
@@ -167,24 +167,18 @@ parameter must be adjusted together with `progressCallbacksInterval` parameter.
167
167
*`.off()` All events are removed.
168
168
*`.off(event)` Remove all callbacks of specific event.
169
169
*`.off(event, callback)` Remove specific callback of event. `callback` should be a `Function`.
170
-
*`.upload()` Start or resume uploading.
171
-
*`.pause()` Pause uploading.
172
-
*`.resume()` Resume uploading.
173
-
*`.cancel()` Cancel upload of all `FlowFile` objects and remove them from the list.
170
+
*`.upload()`[async]Start or resume uploading.
171
+
*`.pause()`[async]Pause uploading.
172
+
*`.resume()`[async]Resume uploading.
173
+
*`.cancel()`[asyc]Cancel upload of all `FlowFile` objects and remove them from the list.
174
174
*`.progress()` Returns a float between 0 and 1 indicating the current upload progress of all files.
175
175
*`.isUploading()` Returns a boolean indicating whether or not the instance is currently uploading anything.
176
-
*`.addFile(file, event = null, initFileFn = undefined)` Add a HTML5 File object to the list of files.
176
+
*`.addFile(file, event = null, initFileFn = undefined)`[async]Add a HTML5 File object to the list of files.
177
177
* Accept the same `event` and `initFileFn` parameters thant `addFiles` which is used under the hood.
178
-
*`.addFiles([files], event = null, initFileFn = undefined)` Add multiple File objects to the list of files.
178
+
*`.addFiles([files], event = null, initFileFn = undefined)`[async]Add multiple File objects to the list of files and returns the promise of the corresponding FlowFiles.
179
179
*`event` The optional event that trigger the addition (for internal purposes)
180
-
*`initFileFn` An override of Flow.initFileFn
181
-
*`.asyncAddFile(file, event = null, initFileFn = undefined)` Add a HTML5 File object to the list of files.
182
-
*`.asyncAddFiles([files], event = null, initFileFn = undefined)` Add multiple File objects to the list of files.
183
-
*`asyncAddFile` and `asyncAddFiles` rely on the same parameters than they non-async counterparts with one
184
-
difference: They accept an asynchronous `initFileFn` file function and return, in a promise, the corresponding FlowFiles.
185
-
* Note: Calling `asyncAddFile` or `asyncAddFiles` with no `initFileFn` being defined is aimed identical to there non-async
186
-
counterpart but this may change in the future [TBD].
187
-
*`.removeFile(file)` Cancel upload of a specific `FlowFile` object on the list from the list.
180
+
*`initFileFn` An [async] override of Flow.initFileFn
181
+
*`.removeFile(file)`[asyc] Cancel upload of a specific `FlowFile` object on the list from the list.
188
182
*`.getFromUniqueIdentifier(uniqueIdentifier)` Look up a `FlowFile` object by its unique identifier.
189
183
*`.getSize()` Returns the total size of the upload in bytes.
190
184
*`.sizeUploaded()` Returns the total size uploaded of all files in bytes.
@@ -207,27 +201,16 @@ Events are native, synchronous and provide information about the internal state
207
201
208
202
#### Processing hooks
209
203
210
-
Hooks allows for either synchronous or asynchronous operations and allow altering the regular processing of the file(s) from addition to upload completion.
211
-
It's user responsability to use or not the `async` version of `(async)?addFile` and `(async)?addFiles` according to the behavior of its processing hooks.
212
-
(Defining `async` callbacks for the `asyncAddFile(s)`)
213
-
204
+
Hooks allows for either (possibly asynchronous) operations and allow altering the regular processing of the file(s) from addition to upload completion.
214
205
*`file-added(<FlowFile> file, event) : null` This event is also called before file is added to upload queue and after it's been fully initialized. `event` is the browser `event` object from when the file was added.
215
206
*`files-added([<FlowFile> files], event) : null` Same as `file-added`, but used for multiple file validation.
216
207
*`files-submitted([<FlowFile> files], event) : null` Same as `files-added`, but happens after the file is added to upload queue. Can be used to start upload of currently added files.
217
208
*`filter-file(<FlowFile> file, event) : boolean` The boolean return value decide whether this particular file must be processed or ignored.
218
209
219
210
### Hooks and events format
220
-
- Events and hooks name are case-sensitive, snake-cased and return CustomEvent passed straight to `Flow.on()` callback.
211
+
- Events and hooks name are case-sensitive, snake-cased.
212
+
- In the case of events, a CustomEvent passed straight to callback passed to `Flow.on()`.
221
213
- Sample use `flow.on('file-removed', ({detail: [file]}) => { ... });`
222
-
- In an attempt of backward compatibility, some support of camelCase events exist:
if (files instanceof CustomEvent) { // Handle v3+ events
226
-
var [files, event] = files.detail;
227
-
}
228
-
// Do something with files
229
-
});
230
-
```
231
214
232
215
### FlowFile
233
216
FlowFile constructor can be accessed in `Flow.FlowFile`.
@@ -250,11 +233,12 @@ FlowFile constructor can be accessed in `Flow.FlowFile`.
250
233
251
234
*`.progress(relative)` Returns a float between 0 and 1 indicating the current upload progress of the file. If `relative` is `true`, the value is returned relative to all files in the Flow.js instance.
252
235
*`.pause()` Pause uploading the file.
253
-
*`.resume()` Resume uploading the file.
254
-
*`.cancel()` Abort uploading the file and delete it from the list of files to upload.
255
-
*`.retry()` Retry uploading the file.
256
-
*`.bootstrap()` Rebuild the state of a `FlowFile` object, including reassigning chunks and XMLHttpRequest instances.
236
+
*`.resume()`[async]Resume uploading the file.
237
+
*`.cancel()`[async]Abort uploading the file and delete it from the list of files to upload.
238
+
*`.retry()`[async]Retry uploading the file.
239
+
*`.bootstrap()`[async / internal use only]Rebuild the state of a `FlowFile` object, including reassigning chunks and XMLHttpRequest instances.
257
240
*`.isUploading()` Returns a boolean indicating whether file chunks is uploading.
241
+
*`.isReading()` Returns a boolean indicating whether the file/stream is being read.
258
242
*`.isComplete()` Returns a boolean indicating whether the file has completed uploading and received a server response.
259
243
*`.sizeUploaded()` Returns size uploaded in bytes.
260
244
*`.timeRemaining()` Returns remaining time to finish upload file in seconds. Accuracy is based on average speed. If speed is zero, time remaining will be equal to positive infinity `Number.POSITIVE_INFINITY`
* @return {bool} In the case of *filters*, indicates whether processing must continue.
313
-
* @return null In the case of *actions*.
314
-
*/
315
-
hook(name, ...args){
316
-
letvalue,
317
-
preventDefault=false,
318
-
isFilter=this.isFilter(name),
319
-
callbacks=this._hooks[name]||[];
320
-
321
-
for(letcallbackofcallbacks){
322
-
// console.log(`[event] Fire hook "${name}"${args.length ? ' with ' + args.length + ' arguments' : ''}`);
323
-
value=callback.apply(this,args);
324
-
if(name==='file-added'&&value===false){
325
-
console.warn('In Flow.js 3.x, file-added event is an action rather than a filter. Return value is ignored but removing the `file` property allows to skip an enqueued file.');
0 commit comments