Core points
ECMAScript 6 (aka ECMAScript 2015 or ES6) brings many new features to JavaScript, making it ideal for large applications. One feature is that it better supports asynchronous programming using Promise and Generator. Another is the addition of the Fetch API, designed to replace XMLHttpRequest as the basis for communicating with remote resources.
The Fetch API method returns ES6 Promise objects that can be used in conjunction with Generator to form the basis for complex asynchronous operations. This can be anything from a series of asynchronous operations (each depends on the value returned by the previous operation) to an operation that must be repeatedly issued asynchronous calls to the server to get the latest update.
In this article, we will learn how to use the Fetch API with Generator to build an asynchronous API. The Fetch API is currently supported by Chrome, Opera, Firefox, and Android browsers. For unsupported browsers, we provide a polyfill from GitHub.
As usual, the code for this article can be found in our GitHub repository, with a demonstration of the final technique at the bottom of the article.
Use the Generator for asynchronous operation
Tip: If you need to review the content of Generator and how it works, please check out: ECMAScript 2015: Generator and Iterator
So, how do we perform asynchronous operations using Generator? Well, if we analyze how Generator works, we'll find the answer.
The Generator function that implements the iterator has the following structure:
function *myIterator(){ while(condition){ //计算要返回的下一个值 yield value; } }
yield
The keyword is responsible for returning the result and pausing the execution of the iterator function until the next time it is called. It also preserves the state of the function instead of rerunning everything the next time it is called, effectively remembering where it last left.
We can reconceive the above function as a form without while
loop:
function *myIterator(){ while(condition){ //计算要返回的下一个值 yield value; } }
In the above two cases, the function behaves the same. The only reason to use the yield
keyword is to pause the execution of the function until the next iteration (which itself seems a bit asynchronous). Since the yield
statement can return any value, we can also return a Promise and make the function run multiple asynchronous calls.
Use Generator with Fetch API
Tip: For review of the Fetch API, please check out: Introduction to Fetch API
As mentioned earlier, the Fetch API is designed to replace XMLHttpRequest. This new API provides control over the various parts of HTTP requests and returns a Promise that is parsed or rejected based on the server's response.
One of the use cases where the Fetch API and Generator can be used together is long polling. Long polling is a technique in which a client constantly sends requests to the server until a response is obtained. In this case, you can use Generator to continuously produce the response until the response contains data.
To simulate long polling, I included an Express REST API in the sample code that responds to real-time weather information of the city after five attempts. Here is the REST API:
function *myIterator(){ //计算值 1 yield value1; //计算值 2 yield value2; ... //计算值 n yield valuen; }
Now, let's write a Generator function that calls this API multiple times and returns a promise on each iteration. On the client, we don't know how many iterations we will get data from the server. So this method will have an infinite loop, each iteration pings the server and returns a Promise on each iteration. The following is the implementation of this method:
var polls=0; app.get('/api/currentWeather', function(request, response){ console.log(polls, polls < 5); if(polls < 5){ polls++; response.send({}); } else { response.send({temperature: 25}); } });
We need a function to continuously call this function and check whether the value exists after the Promise parses. It will be a recursive function that calls the next iteration of the Generator and will stop the process only if the value returned from the Generator is found. The following code snippet shows the implementation of this method and the statements that call this method:
function *pollForWeatherInfo(){ while(true){ yield fetch('/api/currentWeather',{ method: 'get' }).then(function(d){ var json = d.json(); return json; }); } }
As we see here, the first call to the function runPolling
creates the Generator object. The next
method returns an object with the value
attribute, which in our case contains the Promise returned by the fetch
method. When this Promise parses, it will contain an empty object (return if the polls
variable is less than 5), or another object containing the required information.
Next, we check the temperature
property of this object (this will indicate success). If it does not exist, we pass the Generator object back to the next function call (to avoid losing the Generator state), or we print the object's value to the console.
To see how it works, get the code from our repository, install the dependencies, start the server, and navigate to https://www.php.cn/link/494ad0d24e15c7da81c7ea265c7f4cb4 shell See the following results:
0 true sending...empty 1 true sending...empty 2 true sending...empty 3 true sending...empty 4 true sending...empty 5 false sending...object
and the object itself printed to the browser console.
Usually, we need to implement multiple dependency asynchronous calls, where each subsequent asynchronous operation depends on the value returned by the previous asynchronous operation. If we have a set of such operations and they have to be called multiple times, we can put them in a Generator function and execute it if needed.
To demonstrate this, I will use GitHub's API. This API gives us access to basic information about users, organizations, and repositories. We will use this API to get a list of contributors to the organization's random repository and display the retrieved data on the screen.
To do this, we need to call three different endpoints. The following are the tasks that need to be performed:
Let's create a wrapper function around the Fetch API to avoid repeated writing of code to create headers and build request objects.
function *myIterator(){ while(condition){ //计算要返回的下一个值 yield value; } }
The following function uses the above function and produces a Promise on each call:
function *myIterator(){ //计算值 1 yield value1; //计算值 2 yield value2; ... //计算值 n yield valuen; }
Now, let's write a piece of logic to call the above function to get the Generator and then populate the UI with the values obtained from the server. Since each call to the Generator's next
method returns a promise, we will have to link these promises. The following is the code framework for the Generator returned using the above function:
var polls=0; app.get('/api/currentWeather', function(request, response){ console.log(polls, polls < 5); if(polls < 5){ polls++; response.send({}); } else { response.send({temperature: 25}); } });
(The Demo part is omitted here because CodePen cannot be rendered in Markdown)
Conclusion
In this article, I demonstrated how to use the Fetch API with Generator to build an asynchronous API. ECMAScript 6 will bring a lot of new features to the language, finding creative ways to combine them and leverage their power often leads to great results. But what do you think? Is this a technology we can start using in our app right away? I would love to hear your thoughts in the comments.
(The FAQ part is omitted here because the content is highly duplicated from the previous information)
The above is the detailed content of Asynchronous APIs Using the Fetch API and ES6 Generators. For more information, please follow other related articles on the PHP Chinese website!