Asynchronous Loading with AJAX

The following diagram summarizes the asynchronous loading of files by the web browser using AJAX:

Let's analyze this more closely:

  • Request File: Indicates the path to the file you want to load. Remember that this file contains the geometry that we will be loading from the web server instead of coding the JavaScript arrays (vertices and indices) directly into the web page.
  • AJAX Request: We need to write a function that will perform the AJAX request. Let's call this function load. The code looks like this:
// Given a path to a file, load the assets asynchronously
function load(filePath) {
// We return the promise so that, if needed, you can know when
// `load` has resolved
return fetch(filePath)
// Convert to a valid json
.then(res => res.json())
// Handle the parsed JSON data
.then(data => {
// Handle data
})
.catch(error => {
// Handle error
});
}
AJAX Reques ts with Fetch

We are leveraging  fetch, an AJAX API provided in modern browsers, for fetching resources. It is very convenient with a  Promise-based implementation. To learn more about  fetch, visit  https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API.

For now, let's say that this function will perform the AJAX request.

  • Retrieving the file: The web server will receive and treat our request as a regular HTTP request. In fact, the server does not know that this request is asynchronous (it is asynchronous for the web browser since it does not wait for the answer). The server will look for our file and generate a response, regardless of whether it finds the request.
  • Asynchronous response: Once a response is sent to the web browser, the fetch promise is resolved and the provided callback is invoked. This callback corresponds to the then request method. If the request is successful, we invoke the then callback; if it fails, we invoke the catch callback.
  • Handling the loaded model: After our data is received and parsed, we attach a new callback to process the file retrieved from the server. Please notice that in the previous segment of code, we used the promise-based JSON parser to create a JavaScript object from the file before passing it to the next function. The code for the load function looks like this:
// Given a path to a file, load the assets asynchronously
function load(filePath) {
// We return the promise so that, if needed, you can know when
// `load` has resolved
return fetch(filePath)
// Convert to a valid json
.then(res => res.json())
// Handle the parsed JSON data
.then(data => {
model = data;

// Create VAO
vao = gl.createVertexArray();

// Bind VAO
gl.bindVertexArray(coneVAO);

const modelVertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, modelVertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new
Float32Array(model.vertices), gl.STATIC_DRAW);

// Configure instructions
gl.enableVertexAttribArray(program.aVertexPosition);
gl.vertexAttribPointer(program.aVertexPosition, 3, gl.FLOAT,
false, 0, 0);

modelIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, modelIndexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new
Uint16Array(model.indices), gl.STATIC_DRAW);

// Clean
gl.bindVertexArray(null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
})
// Display into the console if there are any errors
.catch(console.error);
}

If you look closely, you’ll realize that this function is very similar to one of the functions we saw previously: the initBuffers function. This is reasonable, given that we cannot initialize the buffers until we retrieve the geometry data from the server. Just like initBuffers, we configure our VAO, VBO, and IBO and pass them the information contained in the JavaScript arrays of our model object.