I am creating a React app that involves several calls to some webapi REST services to do my thing. Part of the app, is the approval flow of some requests. There is a specific role that can create these flows with a UI that consists of:
What I do is allow the user to make changes using Javascript (mostly array operations), while populating an actionbuffer array with the action and the respective data. Eg.
this.actionsBuffer.push({
action: "ADD_STEP",
data: next
});
When the user is happy with the arrangement, she can press the Accept button. What it does is iterating the actionsBuffer array and execute the appropriate REST service which is determined by the action field.
I know my description might seem too detailed but I wanted you to know the context.
Question: My question now is that since the calls are asynchronous how can I guarantee that the actions will execute by this order.
Some code snippets:
This iterates and calls determineAction
onAccept: function (e) {
e.preventDefault();
var self = this;
//console.log("Gonna save:",JSON.stringify(this.state.workflow));
var ret=null;
// First we do actions in actionsBuffer
for(var i=0;i<this.actionsBuffer.length;i++)
{
ret = self.determineAction(this.actionsBuffer[i]);
if (ret==false)
break;
else
this.actionsBuffer.splice(i,1);
ret=null;
}
this.saveAll();
},
And determineAction. Pardon the debugging console messages
determineAction: function (action) {
var url="";
var verb="";
switch(action.action)
{
case "ADD_STEP":
delete action.data.ActorList;
url=this.props.server+"/workflows/"+this.props.workflowid+"/steps";
verb="POST";
break;
case "DELETE_STEP":
url=this.props.server+"/workflows/"+this.props.workflowid+"/delete/";
verb="POST";
break;
}
console.log("Going to call url:",url," with varb:",verb," and data:",action.data);
$.ajax({
type: verb,
url: url,
data: JSON.stringify(action.data),
processData:false,
contentType: 'application/json'
})
.success(function(data) {
return true;
//self.props.onclose(self.state.workflows.WorkflowId);
})
.error(function(jqXhr) {
console.log(jqXhr);
return false;
});
},
You are not waiting for determineAction
to finish. Make it return a promise, and wait for it where you are calling it. Also your loop has to be asynchronous. I've created an attempt that may not be exactly what you need but shows you the direction that you should move.
onAccept: function (e) {
e.preventDefault();
var self = this;
var ret=null;
// First we do actions in actionsBuffer
var i = 0;
function makeRequest() {
self.determineAction(self.actionsBuffer[i]).success(function() {
i++;
if (i >= (self.actionsBuffer.length) {
self.saveAll();
} else {
makeRequest();
}
}).error(function(){
self.saveAll();
})
}
makeRequest()
this.saveAll();
},
determineAction: function (action) {
var url="";
var verb="";
switch(action.action)
{
case "ADD_STEP":
delete action.data.ActorList;
url=this.props.server+"/workflows/"+this.props.workflowid+"/steps";
verb="POST";
break;
case "DELETE_STEP":
url=this.props.server+"/workflows/"+this.props.workflowid+"/delete/";
verb="POST";
break;
}
console.log("Going to call url:",url," with varb:",verb," and data:",action.data);
return $.ajax({
type: verb,
url: url,
data: JSON.stringify(action.data),
processData:false,
contentType: 'application/json'
});
},
Rather than iterating over your array of actions synchronously with a for
loop. Instead, treat it as a queue.
Here's a simple example.
function processActions(actionQueue) {
if(actionQueue.length == 0) return;
// take the first action from the queue
var action = actionQueue[0];
// assuming determineAction() returns a promise
determineAction(action)
.then(function() {
var remainingActions = actionQueue.slice(1);
// we know this action has completed, so we can pass
// the remaining actions to be processed
processActions(remainingActions);
});
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.