Run function right after asynchronous one - javascript

I want to store in chrome.storage ids. Using INSERT_OR_REMOVE("blocked",12) I am adding or removing 12 from database. The thing is that it is working asynchronous. What I want to do is to use colorize function right after. What should I do to archive that?
function INSERT_OR_REMOVE(table, id) {
if (isNaN(id))
return;
var parsed = parseInt(id);
chrome.storage.local.get(table, function (data) {
if (data[table] == null)
data[table] = [];
if (!data[table].includes(id))
data[table].push(id);
else
data[table].remByVal(id);
chrome.storage.local.set(data);
});
}
function colorize() {
chrome.storage.local.get("blocked", function (data) {
var buttons = $("div.base-btn").closest("table");
for (i = 0; i < buttons.length; i++) {
var id = $(buttons[i]).attr("data-id");
if (data["blocked"].includes(id))
$(buttons[i]).parent().addClass('blocked');
else
$(buttons[i]).parent().removeClass('blocked');
}
});
}

Chrome StorageArea.set() accepts a callback function which is run on success/failure. It is identical to the callback you passed to chrome.storage.local.get(table, callbackFunction)
You just need to add colorize as the callback to be run on completing set:
chrome.storage.local.set(data, colorize)

Related

Run ajax request until it returns results

I currently rely on a simple ajax call to fetch some data from our query service api. It is unfortunately not the most robust api and can at times return an empty result set. As such, I want to retry the ajax call until resultSet.length > 0.
I could use setTimeOut and break the loop if I find results, but it seems like an inelegant solution, especially as the time to completion is anywhere between 1s and 6s. I currently have the following, but it doesn't seem to break the loop when needed, and remains inelegant. Any help would be appreciated!
var resultSet = 0;
function fetchQueryData(query, time, iter) {
(function myLoop(i){
if (i == iter) {
fetchData(resultSet, dataset, query);
} else {
setTimeout(function(){
if (resultSet == 0) {
fetchData(resultSet, dataset, query);
}
if (--i) myLoop(i);
}, time)
}
})(iter);
}
fetchQueryData('select * from table', 6000, 5);
function fetchData(resultSet, dataset, query) {
var dataString = 'query=' + encodeURIComponent(query);
$.ajax({
type : "POST",
data: dataString,
url : "/queryapi",
success: function(json) {
var data = [];
var schema = json.data.schema;
var rows = json.data.rows;
if (typeof schema != 'undefined') {
resultSet = 1;
for (var i = 0; i < rows.length; i++) {
var obj = {};
for (var j = 0; j < schema.length; j++) {
obj[schema[j]['name']] = rows[i][j];
}
data.push(obj);
}
}
});
}
Instead of using a setTimeout, wrap the request in a function, and call that same function in the success callback of the request if the returned set is empty.
This will prevent you from sending more than one request to your API at a time, and will also terminate as soon as you get back a satisfactory response.
(In short, you're using recursion instead of an explicit loop.)

making functions that need to be called in order and pass args modular

Hey I'm trying to understand functional programming, stay current etc.
I have this gigantic nested node function tha tI'm attempting to refactor into modules. Each function passes an argument to the next, some are async api calls. I've gotten as far as breaking it down into multiple functions but they're still not really modular as each one calls the next function.
I'm wondered if there's a design pattern to totally untangle them so that the names of the other functions don't appear in the functions but can be passed as callbacks or something. Or maybe that's not even appropriate in this case?
I wrote some simpler fake code that approximates my actual problem so you don't have to sift through endless irrelevant specifics:
function1Async();
function function1Async() {
var theArray = [];
var theData = "";
var theInfo = "";
Async.get( /* api */, function(error, data, response) {
if (error) {
function4(); // function call
}
theData = data[0].infos;
for (i in data) {
theInfo = theData[i].info;
theArray.push(theInfo);
}
function2Async(theArray); // function call
});
}
function function2Async(array) {
var theArray = [];
var theObject = {}
var arrayLength = array.length;
for (let i = 0; i < arrayLength; i++) {
search = '"' + array[i] + '"';
T.get(/* api */, {q: trend, search: 50}, function (error, data, response) {
if (error) {
theArray.push("error");
}
else {
theObject = {
"data": data
}
theArray.push(theObject);
}
if (theArray.length == arrayLength) {
function3(theArray); // function call
}
});
}
}
function function3 (array) {
var theArray = array;
if (theArray.includes("error") == true) {
function5(); // function call
}
else {
function4(theArray); // function call
}
}
function function4(array) {
var file = 'files/data.json';
jsonfile.writeFile(file, array, function(err) {
function5(); // function call
});
}
function function5() {
var file = 'files/data.json';
jsonfile.readFile(file, function(err, obj) {
return res.json(obj);
});
}
Feel free to chime in with any suggestions even if they're not totally related to the question. Like I said I'm just trying to understand this stuff altogether. Thanks.

using $q.all for making synchronous http calls not working angularjs

I have encountered the following problem and I am unable to proceed. I tried some of the solutions that were posted in different question, but couldn't get it to work
In my controller, I have a $scope.init() function. I have a for loop in it which calls a function to make http.get calls to different urls, each url depends on the previous call's data, so I need it to be synchronous
$scope.init = function() {
decodedURL = $routeParams.url;
//evaluate some variables, ampIndex is > -1 here
for( var i=0; ampIndex > -1; ++i)
{
decodedURL = decodedURL.substring(ampIndex+1, decodedURL.length);
ampIndex = decodedURL.indexOf("&");
$scope.getNextList(i);
/* above function call makes the http.get call to the currentURL based on
decodedURL, and the data is stored in variable[i+1], so for the next
iteration, the calls should be synchronous
*/
$q.all(asyncCall).then(function (data) {var j;} );
/* I wrote the above dummy statement so that it is executed only after
http.get in $scope.getNextList() function is successful, but it is
not working
*/
}
};
$scope.getNextList = function(index) {
// $currentURL is calculated
var hello = _helpers.server.http($http, $scope.currentURL) {
.success( function(response) {
})
.error( fucntion(errResponse) {
});
asyncCall.push(hello);
};
How do I solve this problem?
How about something along these lines?
http://plnkr.co/edit/pjWbNX1lnE2HtaNs1nEX?p=preview
$scope.init = function ( ){
for (var i=0; i < 10; i++) {
$scope.getNextList(i) // push calls into array
};
var index = 0;
function makeCall() {
$scope.asyncCall[index]
.success(function(data) {
if (index < $scope.asyncCall.length - 1) {
console.log(index);
index += 1;
makeCall();
}
else {
console.log(index); // last call
}
})
}
makeCall();
};

Callback to prevent looping before completion of ajax

I have read countless examples of similar posts calling for help and also explanations of the theory behind callbacks, but I just can't grasp it. I have gotten to the stage where I'd rather find a solution for my particular scenario and move on even if I don't really understand 'why/how' it works.
I have an ajax call that needs to loop through and need to find a way to prevent the next call before the previous has completed. Could you suggest how I might use a callback or other method to make this happen.
Here's the code (which works, but doesn't run the ajax calls 1-by-1 so I'm getting memory errors and page crashes). The function that runs is quite intensive and can take up to 20 seconds (but as little as 1 second)
function returnAjax(startLoc,startRow)
{
var url='index.php?option=com_productfinderrtw&format=raw&task=goThroughProcess';
var data = 'startloc='+startLoc+'&starttour='+startRow;
var request = new Request({
url: url,
method:'get',
data: data,
onSuccess: function(responseText){
document.getElementById('fields-container').innerHTML= responseText;
//I realise this is where on-success code cneeds to go- is this where the callback belongs?
}
}).send();
}
function iterator (startLoc,startRow) {
if (startRow <20)
{
startRow++;
}
else
{
startRow = 1;
startLoc++;
}
return [startLoc, startRow];
}
function runRAA() {
var startLoc = 0;
var startRow = 1;
while (startLoc < 47)
{
returnAjax(startLoc,startRow);
$counter = iterator(startLoc,startRow);
var newLoc = $counter[0];
var newRow = $counter[1];
startLoc = newLoc;
startRow = newRow;
}
}
runRAA() is the main function that runs on a button press. How can I rearrange this to make sure that returnAjax doesn't run until the previous time is completed?
Thanks in advance for this. I KNOW that similar questions have been asked, so I beg that you don't direct me to other explanations- chances are I've read them but just don't grasp the concept.
Cheers!
PS. I understand that the iterator() function needs to run only when the returnAjax() is complete also, as iterator() sets the new parameter values for each instance of the returnAjax() function
Allow to pass a callback parameter that will be called when the ajax call is completed.
function returnAjax(startLoc, startRow, callback) {
//...
onSuccess: function(responseText) {
document.getElementById('fields-container').innerHTML= responseText;
if (callback) {
callback.apply(this, arguments); //call the callback
}
}
//...
}
Then you can do something like this:
function runRAA(startLoc, startRow) {
startLoc = startLoc || 0;
startRow = startRow || 1;
if (startLoc < 47) {
returnAjax(startLoc, startRow, function (responseText) {
var counter = iterator(startLoc, startRow);
//do something with the response
//perform the next ajax request
runRAA(counter[0], counter[1]);
}));
}
}
runRAA(); //start the process

How to return this value?

I am building a mobile app using phonegap, jQuery and jQuery mobile. I want to use SqLite database in my app for storing some user information. (I can't use local storage i want to do search/sort operations on the data)
This is the code I am working on to get this done,
function getAccountInformation(){
var accounts = {};
db.transaction(function(transaction) {
transaction.executeSql('SELECT * FROM account;', [],
function(transaction, result) {
if (result != null && result.rows != null) {
for (var i = 0; i < result.rows.length; i++) {
var item={};
var row = result.rows.item(i);
for(var prop in row){
item[prop]=row[prop]
}
accounts[i]=item;
}
}
},errorHandler
);
},errorHandler,nullHandler);
console.log(JSON.stringify(accounts));
}
If I put this console.log(JSON.stringify(accounts)); after the end } of the for loop it shows proper output.
But if I put it where it is right now the {} is printed as an output.
How can I make getAccountInformation() function return that accounts object to my other function? Where I will use jQuery to render the output.
What I want to do is return this accounts object simply by wrting
return accounts;
Because the SqLite functions are asynchronous you cannot just return the value.
I would make the getAccountInformation receiving a callback as below:
function getAccountInformation(callbackfn)
{
db.transaction(function(transaction),
.....,
function (transaction, result)
{
if (result != null)
{
callbackfn(result);
}
});
}
In such way you will get your function called when the db request executed.
That depends on when the function is called. When it is called asynchronously (like an AJAX request) you're out of luck. In that case I suggest you read about jQuery deferreds.
A code snippet based on deferreds could look like this:
var deferred = new jQuery.Deferred();
var accounts = {};
deferred.done(function(data) {
// process your data here
});
db.transaction(function(transaction) {
transaction.executeSql('SELECT * FROM account;', [],
function(transaction, result) {
if (result != null && result.rows != null) {
for (var i = 0; i < result.rows.length; i++) {
var item={};
var row = result.rows.item(i);
for(var prop in row){
item[prop]=row[prop]
}
accounts[i]=item;
}
deferred.resolve(accounts); // let the "done" function get called
} else {
deferred.reject();
}
}, errorHandler
);
},errorHandler,nullHandler);
db.transaction and transaction.executeSql produce their results asynchronously through the use of callback functions. This means that your getAccountInformation function will return immediately and will not wait for the transaction to complete (as in a synchronous call).
It's probably easier to simply pass in a callback function as an argument of your getAccountInformation and run that function when the accounts array is populated. Therefore, change your function signature to getAccountInformation(callback) and replace the executeSql callback with:
function(transaction, result) {
if (result != null && result.rows != null) {
for (var i = 0; i < result.rows.length; i++) {
var item={};
var row = result.rows.item(i);
for(var prop in row){
item[prop]=row[prop]
}
accounts[i]=item;
}
callback(accounts); // Call callback function with populated accounts
}
}
You can then call this function with:
getAccountInformation(function(accounts) {
// Do something with the accounts
});
There are fancier ways such as jQuery Deferreds and Promises which makes working with asynchronous functions easier, but you still need to understand why this exists. By using asynchronous actions, your application stays responsive while waiting for results.

Categories

Resources