Flow.js
A JavaScript library providing multiple simultaneous, stable, fault-tolerant and resumable/restartable file uploads via the HTML5 File API.
Install / Use
/learn @flowjs/Flow.jsREADME
Flow.js
<a href="https://www.buymeacoffee.com/aidas" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" style="height: 25px !important;width: 108px !important;" height=25 ></a>
Flow.js is a JavaScript library providing multiple simultaneous, stable and resumable uploads via the HTML5 File API. (Demo)
The library is designed to introduce fault-tolerance into the upload of large files through HTTP. This is done by splitting each file into small chunks. Then, whenever the upload of a chunk fails, uploading is retried until the procedure completes. This allows uploads to automatically resume uploading after a network connection is lost either locally or to the server. Additionally, it allows for users to pause, resume and even recover uploads without losing state because only the currently uploading chunks will be aborted, not the entire upload.
Flow.js does not have any external dependencies other than the HTML5 File API. This is relied on for the ability to chunk files into smaller pieces. Currently, this means that support is limited to Firefox 4+, Chrome 11+, Safari 6+ and Internet Explorer 10+.
Samples and examples are available in the samples/ folder. Please push your own as Markdown to help document the project.
Can I see a demo?
Flow.js + angular.js file upload demo - ng-flow extension page https://github.com/flowjs/ng-flow
JQuery and node.js backend demo https://github.com/flowjs/flow.js/tree/master/samples/Node.js
How can I install it?
Download a latest build from https://github.com/flowjs/flow.js/releases
it contains development and minified production files in dist/ folder.
or use npm:
npm install @flowjs/flow.js
or use bower:
bower install flow.js#~2
or use git clone
git clone https://github.com/flowjs/flow.js
How can I use it?
A new Flow object is created with information of what and where to post:
var flow = new Flow({
target:'/api/photo/redeem-upload-token',
query:{upload_token:'my_token'}
});
// Flow.js isn't supported, fall back on a different method
if(!flow.support) location.href = '/some-old-crappy-uploader';
To allow files to be either selected and drag-dropped, you'll assign drop target and a DOM item to be clicked for browsing:
flow.assignBrowse(document.getElementById('browseButton'));
flow.assignDrop(document.getElementById('dropTarget'));
After this, interaction with Flow.js is done by listening to events:
flow.on('fileAdded', function(file, event){
console.log(file, event);
});
flow.on('fileSuccess', function(file,message){
console.log(file,message);
});
flow.on('fileError', function(file, message){
console.log(file, message);
});
How do I set it up with my server?
Most of the magic for Flow.js happens in the user's browser, but files still need to be reassembled from chunks on the server side. This should be a fairly simple task and can be achieved in any web framework or language, which is able to receive file uploads.
To handle the state of upload chunks, a number of extra parameters are sent along with all requests:
flowChunkNumber: The index of the chunk in the current upload. First chunk is1(no base-0 counting here).flowTotalChunks: The total number of chunks.flowChunkSize: The general chunk size. Using this value andflowTotalSizeyou can calculate the total number of chunks. Please note that the size of the data received in the HTTP might be lower thanflowChunkSizeof this for the last chunk for a file.flowTotalSize: The total file size.flowIdentifier: A unique identifier for the file contained in the request.flowFilename: The original file name (since a bug in Firefox results in the file name not being transmitted in chunk multipart posts).flowRelativePath: The file's relative path when selecting a directory (defaults to file name in all browsers except Chrome).
You should allow for the same chunk to be uploaded more than once; this isn't standard behaviour, but on an unstable network environment it could happen, and this case is exactly what Flow.js is designed for.
For every request, you can confirm reception in HTTP status codes (can be change through the permanentErrors option):
200,201,202: The chunk was accepted and correct. No need to re-upload.404,415.500,501: The file for which the chunk was uploaded is not supported, cancel the entire upload.- Anything else: Something went wrong, but try reuploading the file.
Handling GET (or test() requests)
Enabling the testChunks option will allow uploads to be resumed after browser restarts and even across browsers (in theory you could even run the same file upload across multiple tabs or different browsers). The POST data requests listed are required to use Flow.js to receive data, but you can extend support by implementing a corresponding GET request with the same parameters:
- If this request returns a
200,201or202HTTP code, the chunks is assumed to have been completed. - If request returns a permanent error status, upload is stopped.
- If request returns anything else, the chunk will be uploaded in the standard fashion.
After this is done and testChunks enabled, an upload can quickly catch up even after a browser restart by simply verifying already uploaded chunks that do not need to be uploaded again.
Full documentation
Flow
Configuration
The object is loaded with a configuration options:
var r = new Flow({opt1:'val', ...});
Available configuration options are:
targetThe target URL for the multipart POST request. This can be a string or a function. If a function, it will be passed a FlowFile, a FlowChunk and isTest boolean (Default:/)singleFileEnable single file upload. Once one file is uploaded, second file will overtake existing one, first one will be canceled. (Default: false)chunkSizeThe size in bytes of each uploaded chunk of data. This can be a number or a function. If a function, it will be passed a FlowFile. The last uploaded chunk will be at least this size and up to two the size, see Issue #51 for details and reasons. (Default:1*1024*1024, 1MB)forceChunkSizeForce all chunks to be less or equal than chunkSize. Otherwise, the last chunk will be greater than or equal tochunkSize. (Default:false)simultaneousUploadsNumber of simultaneous uploads (Default:3)fileParameterNameThe name of the multipart POST parameter to use for the file chunk (Default:file)queryExtra parameters to include in the multipart POST with data. This can be an object or a function. If a function, it will be passed a FlowFile, a FlowChunk object and a isTest boolean (Default:{})headersExtra headers to include in the multipart POST with data. If a function, it will be passed a FlowFile, a FlowChunk object and a isTest boolean (Default:{})withCredentialsStandard CORS requests do not send or set any cookies by default. In order to include cookies as part of the request, you need to set thewithCredentialsproperty to true. (Default:false)methodMethod to use when POSTing chunks to the server (multipartoroctet) (Default:multipart)testMethodHTTP method to use when chunks are being tested. If set to a function, it will be passed a FlowFile and a FlowChunk arguments. (Default:GET)uploadMethodHTTP method to use when chunks are being uploaded. If set to a function, it will be passed a FlowFile and a FlowChunk arguments. (Default:POST)allowDuplicateUploadsOnce a file is uploaded, allow reupload of the same file. By default, if a file is already uploaded, it will be skipped unless the file is removed from the existing Flow object. (Default:false)prioritizeFirstAndLastChunkPrioritize first and last chunks of all files. This can be handy if you can determine if a file is valid for your service from only the first or last chunk. For example, photo or video meta data is usually located in the first part of a file, making it easy to test support from only the first chunk. (Default:false)testChunksMake 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)preprocessOptional function to process each chunk before testing & sending. To the function it will be passed the chunk as parameter, and should call thepreprocessFinishedmethod on the chunk when finished. (Default:null)changeRawDataBeforeSendOptional 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. Usage example can be seen #276. (For more, check issue #170).initFileFnOptional function to initialize the fileObject. To the function it will be passed a FlowFile and a FlowChunk arguments.readFileFnOptional function wrapping reading op
