Skip to content

Web API Polyfills (experimental)

Madhav Varshney edited this page Jan 24, 2019 · 22 revisions

These APIs are still in experiment, we're trying to make file access related Web API polyfills so that browser libraries which uses Blob, File, FileReader ..etc. can still work in React Native.

XMLHttpRequest

0.8.0

Replacing window.XMLHttpRequest will break the functionality of official fetch polyfill since it's base on XMLHttpRequest polyfill. However, fetch replacement and RNFetchBlob.fetch are still working and has more features, consider use them as an alternative of fetch when using XMLHttpRequest polyfill.

Though React Native already have XMLHttpRequest polyfill, but it's not a complete implementation, for example, it's not extended EventTarget, and it does not support Blob. Our XMLHttpRequest polyfill has good integration with RNFetchBlob.fs API, because it uses RNFetchBlob.fetch under the hood. Also it's built for compatible with browser libraries.

Static Properties

0.8.2

binaryContentTypes:Array (NON-STANDARD)

An array contains MIME type string, when response Content-Type contains substring in this array, the data will be automatically converted to Blob().

Static Methods

addBinaryContentType(val:string) (NON-STANDARD)

0.8.2

Add a binaryContentType to XMLHttpRequest.binaryContentTypes.

removeBinaryContentType(val:string) (NON-STANDARD)

0.8.2

Remove a binaryContentType from XMLHttpRequest.binaryContentTypes.

setLog(level:number)

0.9.4

Enable logs from polyfill, level should be a number, when level is -1 disable logs.

Properties

readState:number (readonly)

The state of XMLHttpRequest

name value
UNSENT 0 Initial state, The object has been constructed.
OPENED 1 State after successfully invoke open(), you can setRequestHeader(), and send() during state.
HEADERS_RECEIVED 2 All redirects (if any) have been followed and all HTTP headers of the final response have been received.
LOADING 3 The request is receiving response body. Started to triggering onprogress events.
DONE 4 Response data completely received.

responseType : '' | 'blob' | 'text' | 'son'

Set this property will change the type of response.

response: string | Object | Blob

The response data, its type is decided by Content-Type in response header. This is the strategy so far :

  1. If the Content-Type field contains string text/plain the response data will be string, and XMLHttprequest.responseType will be text
  2. If the Content-Type field contains string application/json the response data will be an Object, and XMLHttprequest.responseType will be json
  3. Otherwise it would be a Blob, and XMLHttprequest.responseType will be blob

XMLHttpRequest():XMLHttpRequest

Constructor, does not accept any argument.

open(method, url, async, user, password)

method: string

url: string

async:?true (NOT IMPLEMENTED)

user:string (NOT IMPLEMENTED)

password:string (NOT IMPLEMENTED)

This method simply sets the request destination of XMLHttpRequest and change readystate to OPENED when finished.

setRequestHeader(name, value)

name: string

value: string

Set request header, this method can only be called after readstate is OPENED, otherwise it will throw an InvalidStateError.

overrideMimeType(mime)

mime: string

TODO

send(body)

body: string | Blob | Array

Send request with the given body, this method can only be called when readstate is OPENED, otherwise it will throw an InvalidStateError.

Blob

0.8.0

Blob(Binary Large Object) usually contains a reference to a binary data which stored in file, and it is used very often in HTML5 when upload and download file. Blob object can be created by directly pass an Array, ArrayBuffer, ArrayBufferView, or an array contains mix of any of such objects to its constructor. In RNFetchBlob, you can also create a Blob object from string, BASE64 encoded string, and path of a file by specifying correspond content type to the Blob object.

Properties

size:number

type:string

isRNFetchBlobPolyFill:boolean (NON-STANDARD)

Events

Static Methods

clearCache():Promise (NON-STANDARD)

This static method remove any blob files in storage, it's useful when you're going to clean up the cache folder.

build(data, options):Promise

Similar to Constructor but the Blob instance will resolved by a promise

const Blob = RNFetchBlob.polyfill.Blob
Blob.build(SOME_BASE64_ENCODED_DATA, { type: 'image/png;base64' })
    .then((blob) => {
        // do something with the Blob
    })

setLog(level:number)

0.9.4

Enable logs from Blob polyfill, level should be a number, when level is -1 disable logs.

Constructor(data, options)

data: string | FormData | Blob | Array

options : ?{ type : string, endings : (NOT SUPPORTED) }

The content of Blob object will always stored in file system ( in DocumentDir/RNFetchBlob-blob/). You should manage these files manually. RNFetchBlob automatically decide how to store the Blob object by checking options.type and type of data. In the following steps :

  1. If type of data is a Blob, it will create a new file which copies data from given Blob object as its content.
  2. Else if the data is a String which starts with prefix RNFetchBlob-file://, it simply uses the existing file as its content. However if it does not have the prefix, RNFetchBlob will check if options.type is a string contains application/octet or ;BASE64. If it does, create a file by decode the string using BASE64 decoder. If it does not, write the string to file as utf8 string.
  3. Else if the data is an ArrayBuffer, it will be created using the bytes in array buffer (simply applying RNFetchBlob.fs.writeFile(path, data, 'ascii')). (NOT IMPLEMENTED)
  4. Else create Blob by store the data as utf8 string text file.

Basically you can create a RNFetchBlob flavor Blob object in these way (use Blob.build)

import RNFetchBlob from 'rn-fetch-blob'

const Blob = RNFetchBlob.polyfill.Blob

// create a blob from BASE64 encoded string, the ';base64' in `type` is crucial
Blob.build(BASE64_ENCODED_STRING, { type : 'image/png;base64' })
    .then((blob) => { ... })

// create a blob which has content of a file
Blob.build(RNFetchBlob.wrap(PATH_TO_A_FILE), { type : 'text/plain' })
    .then((blob) => { ... })

// create a blob from another blob
Blob.build('foo', { type : 'text/plain' })
    .then( (first_blob) => Blob.build(first_blob, { type : 'text/plain' }) )
    .then( (second_blob) => { ... } )

// create a blob from mice-typed array, e.g multipart form data
Blob.build(['--806254942825131805744870237569977¥r¥n',
          'Content-Type: application/json; charset=utf-8¥r¥n¥r¥n',
          '{"name":"rn-firebase-upload/image.png","contentType":"image/png"}¥r¥n',
          '--806254942825131805744870237569977¥r¥n',
          'Content-Type: image/png¥r¥n¥r¥n', 
          blob, 
          '--806254942825131805744870237569977--'
        ])
    .then((blob) => { ... })

Keep in mind that in RNFetchBlob the creation process is asynchronous, blob data becomes available after onCreated event triggered. This is not a part of Blob object standard, however this helps you create Blob object easier.

Instance Methods

Slice(start, end, contentType):Blob

0.9.2

This is a synchronous method which immediately returns a Blob object after invoked just like what it is in W3C spec. However, there's a caveat, due to limitation of React Native architecture, there the method is doing asynchronously under the hood, therefore if you're going to access the content of its returned object, you should still register an event handler via Blob.onCreated() insure the object is initialized.

blob.slice(0, 262144).onCreated((slicedBlob) => {
    // get path of sliced blob object
    let path = blob.getRNFetchBlobRef()
    // read content of sliced blob
    fs.readFile(path, 'utf8').then((data) => {
        // there we go !
    })
})

However, you can use it as it's sync when dealing with Web API polyfills, because poyfills will take care of the asychrnous problem under the hood.

let xhr = new XMLHttpRequest()
// use blob.slice as if it's synchronous
xhr.send(blob.slice(0, 262144, 'octet-binary'))

start:number

An index into the Blob indicating the first byte to include in the new Blob. If you specify a negative value, it's treated as an offset from the end of the string toward the beginning. For example, -10 would be the 10th from last byte in the Blob. The default value is 0. If you specify a value for start that is larger than the size of the source Blob, the returned Blob has size 0 and contains no data.

end:number

An index into the Blob indicating the first byte that will not be included in the new Blob (i.e. the byte exactly at this index is not included). If you specify a negative value, it's treated as an offset from the end of the string toward the beginning. For example, -10 would be the 10th from last byte in the Blob. The default value is size.

contentType:?number (Optional)

The content type to assign to the new Blob; this will be the value of its type property. The default value is an empty string.

onCreated(handler):void

handler:(Blob) => void

Register an event handler that will be invoked when blob constructor finished the creation process, if the object already created, the handler will be invoked instantly.

safeClose()

0.10.5

An alternative to close(), this method also release the resources but it does not remove the Blob from disk if it's created from an existing file.

Blob.build(RNFetchBlob.wrap(PathOfSomeFile))
  .then((blob) => {
    // the file at `PathOfSomeFile` will be removed too !
    // blob.close()
    // the source file will not be removed
    // blob.safeClose()
  })

close()

0.8.0

Remove the blob content release the resource from storage. Beware that If the blob is created from an existing file path, the original file will BE REMOVED when blob.close() since the blob simply uses the same file as it's content (for performance concern).

File

0.8.0

Description on MDN

A File object is a specific kind of a Blob, and can be used in any context that a Blob can. In particular, FileReader, URL.createObjectURL(), createImageBitmap(), and XMLHttpRequest.send() accept both Blobs and Files.

Static Method

File.build(filename, data, contentType):File

A method overrides Blob.build but it take on extra argument filename, which will be set as the instance's filename property.

EventTarget

0.8.0

TODO

XMLHttpRequestEventTarget

0.8.0

TODO

ProgressEvent

0.8.0

TODO

Clone this wiki locally