Class structure
First, let’s set up a shelf and list all the variables that need to be used. We need an array to save the callback function list; we need a flag to indicate whether the asynchronous operation has been completed; we can also learn IAsyncResult and add a state to allow the implementer of the asynchronous operation to expose the custom execution status; finally add a Variables hold the results of asynchronous operations.
Async = {
Operation: {
var callbackQueue = [];
this.result = undefined;
this.state = "waiting";
this.completed = false;
}
}
addCallback method Next, we have to implement the addCallback method. Its job responsibility is very simple, which is to put the callback function into the callbackQueue. In addition, if completed is true at this time, it means that the asynchronous operation has yielded, and this callback will be called immediately.
this.yield = function(callback) {
callbackQueue.push(callback);
if (this.completed) {
this.yield(this.result);
}
return this;
}
We assume that the yield method will take out the callback functions in the callbackQueue one by one and then call them. Therefore, if completed is true, just call yield again using the existing result, so that yield will naturally call the callback function added to the callbackQueue this time. callback function.
As for the final return this;, it is just to facilitate jQuery-style chain writing. Multiple callback functions can be added continuously by dot separation:
asyncOperation(argument)
.addCallback(firstCallback)
.addCallback(secondCallback);
yield method Finally, we have to implement the yield method. It needs to take out the callback functions in the callbackQueue one by one, and then call them all again, and ensure that this operation is asynchronous.
this.yield = function(result) {
var self = this;
setTimeout(function() {
self.result = result;
self.state = "completed";
self.completed = true;
while (callbackQueue. length > 0) {
var callback = callbackQueue.shift();
callback(self.result);
}
}, 1);
return this;
}
By using setTimeout, we ensure that the actual operation of yield is asynchronous. Then we update the yield results and related status passed in by the user to the object properties, and finally traverse the callbackQueue to call all callback functions.
Summary In this way, we have made a simple JavaScript asynchronous calling framework. The complete code can be seen here: Asynchronous calling framework Async.Operation.
This framework can well solve the problem of coexistence of synchronous and asynchronous operations in the call stack. Assuming that all functions return Async.Operation, users of the framework can use a unified mode to write code and handle function returns. There is no need to care whether this function actually returns synchronously or asynchronously.
For serial calls to multiple asynchronous functions, we can now write them in a nested addCallback manner, but as the number of nesting levels increases, the code will become more and more unsightly:
firstAsyncOperation().addCallback(function() {
secondAsyncOperation() .addCallback(function() {
thirdAsyncOperation().addCallback(function() {
finalSyncOperation();
});
});
});
Can we change the nested form to jQuery-style chain writing? This is the question we want to think about next, if you don’t want to miss the relevant discussion