An ArrayBuffer is more than just a simple array. It contains raw binary data. This is very useful for direct memory manipulation and conserving space.
When you create a normal array, you won't get a proper set of contiguous memory in many cases since arrays can contain any combination of different kinds of objects. This is useful when you have dynamic data and multiple types together (frequently happens in JS) but is not so useful when you know the exact layout of memory that you need.
This also allows you to view the data at the byte level. For example, it's pretty common in binary data formats to have a n byte long identifier number, an m byte long field telling you how many bytes are used for this field, and m' bytes of data that actually makes up the data field.
[ identifier ][ bytes of data ][ data ]
With an ArrayBuffer, you have the option of moving through that data on the byte level by using various Views. A regular array doesn't allow you to move through the data with that level of granularity because no guarantees are made about the memory layout.
Finally, because you are telling the compiler/interpreter exactly how much space you're going to use and exactly how you're going to view it, it can do much more advanced optimizations when working with that data. When iterating through that data, it doesn't have to make calculated leaps through memory. Instead, it knows exactly how far to move ahead in memory to find the next data point.
As for what Uint8Array is, it's a typed array. Essentially, it tells the compiler/interpreter that you will be accessing this data exclusively as 8-bit uints which, again, allows it to make better optimizations. Then you can use standard array indexing on it (arr[0], arr[1], etc.) and you'll be getting back the equivalent uint values out of the array.
TL;DR They take less space when the exact data format is known, allows you to move more exactly through your data and gives the compiler/interpreter greater options for optimization.
Answer from Mike Cluck on Stack Overflowwebgl - Difference between "buffer" and "array" in OpenGL? - Game Development Stack Exchange
scala - What is the difference between ArrayBuffer and Array - Stack Overflow
What is the difference between an ArrayBuffer and a Blob?
Difference between an ArrayBuffer and a Blob
The naming of Vertex Array Object is somewhat unfortunate. There's three different things that appear (used to appear) in/with/around your application, and which are (have been, historically) named differently, with "array" or "buffer" in the name (well, there's framebuffer objects too, but I'll ignore that).
- Data that lives in your application, formally and factually, but which is pulled by OpenGL in one go (as opposed to vertex-by-vertex). This was once upon a time what you would call vertex array.
The intent of this was to make accessing more efficient since OpenGL could just copy the whole thing in one go at a well-defined time when you gave the promise that data was consistent, and push it over AGP or whatever in one block. This no longer exists. - Data obscured and accessible by a handle that can be "bound", i.e. made active. Data may factually live in main memory, or on the graphics card, or be moved to a PCIe-mappable region, whatever, but either way you formally do not own (even if it is physically in RAM and if the data came from your application) it -- unless you have currently "mapped" it via the corresponding API, getting back a writeable (and sometimes readable) pointer. You are also limited in your ability of controlling what happens to the data at all (you can give some hints, but that's pretty much it).
OpenGL may move this data around more or less freely, and you are only ever allowed/able to copy to/from the buffer via the corresponding API or access the data while it is being mapped. That is what you call a buffer object (vertex buffer object if it contains vertices, but it really doesn't have to, could as well be image data or uniforms, only vertices were the first to be supported, once upon a time).
The intent of this is to guarantee that OpenGL can (in principle) do what it wants, it can even push the buffer over PCIe speculatively before you even draw. That works because you do not own the data (OpenGL does!) and you can only access it via the given API, so it is known at all times that data is valid. The driver can even opt to throw away buffer memory on the graphics card when it needs memory for something different and later restore it from its secret copy when needed. - A really stupid misnomer for which a much better name would be something like buffer-set or descriptor-set, this is the infamous vertex array object. It is, from your point of view, nothing but a set of buffer handles bunched together under another obscure handle (which you can bind). As it happens, reality is a bit more complicated. In fact, VAO is much closer to how the actual hardware works. Graphic cards have a small number (often something like 2, 4, or 8) of descriptor sets (not just for buffers, but also for samplers) with so-and-so-many entries in each, between which they can switch very efficiently.
Now, the intent of the vertex array object is to reduce the number of API calls and to reduce the number of consistency checks that OpenGL must make internally, and of course, to use the hardware as-it-works. If you bind 5 buffers, then each must go through some possibly expensive checks, and each one is a candidate for cache misses in the driver, plus each single one requires communicating with the graphics card to change a descriptor, etc etc. If you instead bind one VAO, the driver can (often) simply switch the descriptor set on the graphics card, and be done.
A Vertex Array Object (VAO) is an object which contains one or more Vertex Buffer Objects and is designed to store the information for a complete rendered object.
(pulled from khronos)
Each buffer tends to constitute one attribute of a vertex array (object). A VAO can contain many vertex attributes (e.g. position, color, UV). Each might be held in its own buffer, where buffer indicates an unformatted series of contiguous bytes, and where you need to explicitly specify the size (type) per buffer element for both CPU side OpenGL calls and GPU-side shader work.
That's one way. The other ways this can work are:
- All of the attributes are stored interleaved in a single buffer, OR
- Some of the attributes exist in their own dedicated buffers, while others share buffers.
The below diagram illustrates these latter two cases.

Bottom line: If the phrase "vertex array" is used unqualified in OpenGL, you can assume it means VAO, which, in an OpenGL context (specifically) is a very different thing indeed from a buffer.
EDIT re your comment: GL_ARRAY_BUFFER indicates an intention to use that buffer object for vertex attribute data, as described above. This is because buffers are not used only for vertex attributes. However, as it is the most common use-case and you are asking about VAOs, I won't go into the others; here however is a list of the other types of buffers that can be set up.
Both Array and ArrayBuffer are mutable, which means that you can modify elements at particular indexes: a(i) = e
ArrayBuffer is resizable, Array isn't. If you append an element to an ArrayBuffer, it gets larger. If you try to append an element to an Array, you get a new array. Therefore to use Arrays efficiently, you must know its size beforehand.
Arrays are implemented on JVM level and are the only non-erased generic type. This means that they are the most efficient way to store sequences of objects – no extra memory overhead, and some operations are implemented as single JVM opcodes.
ArrayBuffer is implemented by having an Array internally, and allocating a new one if needed. Appending is usually fast, unless it hits a limit and resizes the array – but it does it in such a way, that the overall effect is negligible, so don't worry. Prepending is implemented as moving all elements to the right and setting the new one as the 0th element and it's therefore slow. Appending n elements in a loop is efficient (O(n)), prepending them is not (O(n²)).
Arrays are specialized for built-in value types (except Unit), so Array[Int] is going to be much more optimal than ArrayBuffer[Int] – the values won't have to be boxed, therefore using less memory and less indirection. Note that the specialization, as always, works only if the type is monomorphic – Array[T] will be always boxed.
The one other difference is, Array's element created as on when its declared but Array Buffer's elements not created unless you assign values for the first time.
For example. You can write Array1(0)="Stackoverflow" but not ArrayBuffer1(0)="Stackoverflow" for the first time value assignments.
(Array1 = Array variable & ArrayBuffer1 = ArrayBuffer variable)
Because as we know, Array buffers are re-sizable, so elements created when you insert values at the first time and then you can modify/reassign them at the particular element.
Array:
Declaring and assigning values to Int Array.
val favNums= new ArrayInt
for(i<-0 to 19){
favNums(i)=i*2
}
favNums.foreach(println)
ArrayBuffer:
Declaring and assigning values to Int ArrayBuffer.
val favNumsArrayBuffer= new ArrayBuffer[Int]
for(j<-0 to 19){
favNumsArrayBuffer.insert(j, (j*2))
//favNumsArrayBuffer++=Array(j*3)
}
favNumsArrayBuffer.foreach(println)
If you include favNumsArrayBuffer(j)=j*2 at the first line in the for loop, It doesn't work. But it works fine if you declare it in 2nd or 3rd line of the loop. Because values assigned already at the first line now you can modify by element index.
This simple one-hour video tutorial explains a lot.
https://youtu.be/DzFt0YkZo8M?t=2005
Summary
Unless you need the ability to write/edit (using an ArrayBuffer), then Blob format is probably best.
Detail
I came to this question from a different html5rocks page., and I found @Bart van Heukelom's comments to be helpful, so I wanted to elevate them to an answer here.
I also found helpful resources specific to ArrayBuffer and Blob objects. In summary: despite the emphasis on Blob being immutable/"raw data" Blob objects are easy to work with.
Resources that compare / contrast ArrayBuffer vs Blob:
- Mutability
- an
ArrayBuffercan be changed (e.g. with aDataView) - a
Blobis immutable
- an
- Source / Availability in Memory
- Quoting Bart van Heukelom:
- An ArrayBuffer is in the memory, available for manipulation.
- A Blob can be on disk, in cache memory, and other places not readily available
- Access Layer
ArrayBufferwill require some access layer like typed arraysBlobcan be passed directly into other functions likewindow.URL.createObjectURL, as seen in the example from OP's URL.- However, as Mörre points out you may still need
File-related interfaces and API's likeFileReaderto work with a Blob.
- However, as Mörre points out you may still need
- Convert / Generate
- You can generate
BlobfromArrayBufferand vice versa, which addresses the OP's "Aren't both containers comprised of bits?" - ArrayBuffer can be generated from a Blob using the
FileReader'sreadAsArrayBuffermethod , or the async methodconst arrayBuffer = await blob.arrayBuffer()(thanks to @Darren G) - Blob can be generated from an ArrayBuffer as @user3405291 points out
new Blob([new Uint8Array(data)]);, shown in this answer
- You can generate
- Use in Other Libraries
jsZip;(new JSZip()).loadAsync(...)accepts bothArrayBufferandBlob:String/Array of bytes/ArrayBuffer/Uint8Array/Buffer/Blob/Promise
- How does protocol handle ArrayBuffer vs Blob
- Websocket (aka WS / WSS)
- Use the webSocket's
binaryTypeproperty (could have values "arraybuffer" or "blob") to "control the type of binary data being received over the WebSocket connection."
- Use the webSocket's
- XmlHttpRequest (aka XHR)
- Use the xhr's
responseTypeproperty to "to change the expected response type from the server" (valid values include "arraybuffer", "blob", and others like "document", "json", and "text") -
the response property will contain the entity body according to
responseType, as an ArrayBuffer, Blob, Document, JSON, or string.
- Use the xhr's
- Websocket (aka WS / WSS)
Other helpful documentation:
ArrayBuffer
The
ArrayBufferobject is used to represent a generic, fixed-length raw binary data buffer. You cannot directly manipulate the contents of anArrayBuffer; instead, you create one of the typed array objects or aDataViewobject which represents the buffer in a specific format, and use that to read and write the contents of the buffer.
Blob
A
Blobobject represents a file-like object of immutable, raw data.Blobrepresent data that isn't necessarily in a JavaScript-native format. TheFileinterface is based onBlob, inheriting blob functionality and expanding it to support files on the user's system.
It's explained on the page.
ArrayBuffer
An ArrayBuffer is a generic fixed-length container for binary data. They are super handy if you need a generalized buffer of raw data, but the real power behind these guys is that you can create "views" of the underlying data using JavaScript typed arrays. In fact, multiple views can be created from a single ArrayBuffer source. For example, you could create an 8-bit integer array that shares the same ArrayBuffer as an existing 32-bit integer array from the same data. The underlying data remains the same, we just create different representations of it.
BLOB
If you want to work directly with a Blob and/or don't need to manipulate any of the file's bytes, use xhr.responseType='blob':
I’m always ending up guessing.. I need to somehow understand. I have no idea what I’m doing when working with files. Just trying stuff until it works. Someone plz ELI5..
My current issue is getting a png file from Firebase storage which gives a “file” which I’m trying to add on a pdf, where the library expects a Uint8Array or Arraybuffer. I’ve been doing similar things before. But end up just guessing my way until it works, and this time.. well it doesn’t work. I guessed it all with no success. I don’t know what I’m doing so I guess I need to actually learn ;)