In real-world development, it is common to perform a series of synchronous asynchronous operations sequentially. Or with the Baidu Hi Web version of the example, we have to get the contact list asynchronously, and then asynchronously get each contact's specific information, and the latter is paged get, each request sent 10 contact names and then retrieve the corresponding specific information. This is the number of asynchronous requests that require sequential execution.
To do this, we need to design a new way to optimize the readability of the code, so that the sequential asynchronous operation code looks as elegant as the traditional sequential synchronous operation code.
Traditional Practices
Most programmers can have a good understanding of sequential code, such as this:
Copy Code code as follows:
var firstresult = firstoperation (initialargument);
var secondresult = secondoperation (Firstresult);
var finalresult = thirdoperation (Secondresult);
alert (Finalresult);
The function that executes first provides the required data for the function that is executed later. However, after using our asynchronous invocation framework, the same logic must become this:
Copy Code code as follows:
Firstasyncoperation (initialargument). Addcallback (function (firstresult) {
Secondasyncoperation (Firstresult). Addcallback (function (secondresult) {
Thirdasyncoperation (Secondresult). Addcallback (function (finalresult) {
alert (Finalresult);
});
});
});
Chain Style
I think the code above is really too bad, and I want to be able to transform it into a jquery-style chain. To do this, we first construct a use case:
Copy Code code as follows:
Async.go (initialargument)
. Next (Firstasyncoperation)
. Next (Secondasyncoperation)
. Next (Thirdasyncoperation)
. Next (function (Finalresult) {alert (finalresult);})
In this use case, we pass in the initialization data in the go, and then pass each next with a data processing function that processes the data sequentially.
simultaneous Coexistence
All of the above use case calls are asynchronous functions, but we'd better be able to be compatible with synchronization functions so that the user does not need to care about the implementation of the function. So let's write another use case like this:
Copy Code code as follows:
Async.go (0)
. Next (function (i) {alert (i); return i + 1;})
. Next (function (i) {
alert (i);
var operation = new Async.operation ();
settimeout (function () {Operation.yield (i + 1);}, 1000);
return operation;
})
. Next (function (i) {alert (i); return i + 1;})
. Next (function (i) {alert (i); return i;});
In the above use cases, we expect to see a sequence of hints for 0, 1, 2, and 3, and between 1 and 2 intervals of 1000 milliseconds.
Asynchronous Nature
A chained call is essentially an asynchronous call, so it returns a operation instance as well. This example naturally has the fields of result, state, and completed, and when the entire chained call completes, the results are equal to the outcome returned by the last call, and completed naturally equals true.
We can extend the previous use case to get the following use case code:
Copy Code code as follows:
var chainoperation = async.go (0)
. Next (function (i) {alert (i); return i + 1;})
. Next (function (i) {
alert (i);
var operation = new Async.operation ();
settimeout (function () {Operation.yield (i + 1);}, 1000);
return operation;
})
. Next (function (i) {alert (i); return i + 1;})
. Next (function (i) {alert (i); return i;});
Settiemout (function () {alert (Chainoperation.result;}, 2000);
Saves the return of a chained call, and when the chained call completes, its result should be consistent with the return of the last operation. In the above use case, that is, 3.
Call time
Although we provide a chained invocation, the user does not necessarily have to do so in a fixed way, so we still have to consider the various possible uses of compatible users, such as adding an operation to the call chain asynchronously with Next:
Copy Code code as follows:
var chainoperation = async.go (0);
Chainoperation.next (function (i) {alert (i); return i + 1;});
settimeout (function () {
Chainoperation.next (function (i) {
alert (i);
var operation = new Async.operation ();
settimeout (function () {Operation.yield (i + 1);}, 2000);
return operation;
})
}, 1000);
settimeout (function () {
Chainoperation.next (function (i) {alert (i); return i + 1;});
}, 2000);
In this use case, the user adds an action every 1000 milliseconds, and the second operation takes 2000 milliseconds. That is, the second action is not returned when the third operation is added. As a robust framework, it must be compatible with the way it is used.
In addition, we have to consider that the user may want to construct the call chain first and then execute the call chain. The user then uses the next method to add the action, and then executes it using the Go method.
Copy Code code as follows:
var chainoperation = Async
. chain (function (i) {alert (i); return i + 1;})
. Next (function (i) {
alert (i);
var operation = new Async.operation ();
settimeout (function () {Operation.yield (i + 1);}, 2000);
return operation;
})
. Go (0)
settimeout (function () {
Chainoperation.next (function (i) {alert (i); return i + 1;})
}, 1000);
In the above use case, the user adds a header synchronization operation and a single asynchronous operation through chain and next, then executes the call chain with go, and then asynchronously appends an operation with next, before the call chain executes. A robust framework that should be able to prompt 0, 1, 2, as the user would expect, in such a use case.
Summary
For the needs of chained calls, we have designed so many use cases, including a variety of strange ways of calling asynchronously. How do you end up with such a feature?