This top code inserts adsf into the spreadsheet instead of something else, however the code below logs something else as expected... what's going on here? Set the Apps Script function to myFunction... (P.S. I deleted and updated my previous question with this question)
This code doesn't work as expected:
var obj = {variable:"adsf"};
function myFunction() {
function scheduledScript(plusMonth,plusDay,plusHour,plusMinute) {
obj.variable = "something else";
var now = new Date();
var year = now.getFullYear();
var MONTH = now.getMonth();
var DAY = now.getDate();
var HOUR = now.getHours();
var MINUTE = now.getMinutes();
var seconds = now.getSeconds();
var milliseconds = now.getMilliseconds();
var date = new Date(year,MONTH+plusMonth,DAY+plusDay,HOUR+plusHour,MINUTE+plusMinute,10,0);
ScriptApp.newTrigger('send').timeBased().at(date).create();
}
scheduledScript(0,0,0,1);
}
function send() {
Logger.log(obj.variable); //"adsf"
SpreadsheetApp.openById("1z28v6Y_4kwTxfqXLvEb1Zo81QJGZ8AfxkoSFYP5LM8E").setActiveSelection("H1").setValue(obj.variable);
}
This code works as expected:
var obj = {variable:"asdf"};
function myFunction() {
function process() {
Logger.log(obj.variable); //"asdf"
obj.variable = "something else";
notify();
}
process();
}
function notify () {
Logger.log(obj.variable); //"something else"
}
No confusion there.
Your first script sample sets a time-based trigger which executes send() function. When it executes, it gets the obj global variable value you set in the first line of your code. The trigger does not run your myFunction() function which changes the obj global variable value. Hence you see adsf entered in the spreadsheet cell.
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I am writing a steam bot and am trying to check, if one of the items in a trade is worth below 1 USD. I need to access the "pass" variable, but it never works. Can someone help?
var receive = offer.itemsToReceive;
var pass = true;
receive.forEach(function(id) {
var args = id.split(",");
market.getItemPrice("some app id", some item name).then(function(result) {
var json = JSON.parse(JSON.stringify(result)); // returns e.G $0.08
var price = parseFloat(json.median_price.substring(1));
if(price*100 < 100) {
pass = false;
}
});
});
This question is asked a lot, but hopefully explaining it in your own problem's terms will help you understand.
Your code should wait for any possibility of pass = false;, but it doesn't because you call a asynchronous function --- imagine the code immediately moves on after calling that. Your foreach function is immediately processed and the next line is called until .getItemPrice responds some time later.
So instead, to "wait" for all the results, you can do something like:
var receive = offer.itemsToReceive;
var pass = true;
var itemReceivePromises = receive.map(id=>{
var args = id.split(",");
return market.getItemPrice("some app id", some item name).then(function(result) {
var json = JSON.parse(JSON.stringify(result)); // returns e.G $0.08
var price = parseFloat(json.median_price.substring(1));
if(price*100 < 100) {
pass = false;
}
});
});
Promise.all(itemRecievePromises).then(results=>{
console.log('pass',pass);
});
However, you should pass the "pass" result back through the promise instead of using a higher scoped variable.
I have function in node.js which selects random item from db based on drop chance. Because my friend is lazy to edit drop chances all the time when some item from db is not in stock. I have to calculate those as well.Therefore when the items which is out of stock is selected randomly I need to run function again and If it is out of stock I need to run function again to get the one that is in stock.
My question is: How do I repeat function in node.js until I gets desired response ?
My function looks like this.
function fnPickWinnerItem(chances,cb){
var ajChances=chances;
var iRandomNumber=getRandomInt(ajChances[0].chanceStart,ajChances[ajChances.length-1].chanceEnds);
var aDrop=ajChances.map(function(data){
var input=data;
var iGroupId=input.groupId
var iStartChance=input.chanceStart;
var iEndChance=input.chanceEnds;
var jResponse={"groupId":iGroupId, "status":"win"}
var jResponseFalse={"groupId":"none", "status":"false"}
if(iStartChance<=iRandomNumber&&iRandomNumber<=iEndChance){
// var response= select from db & validate -> if ok return true else
false
if(response){
return jResponse;
}
else{run function again}
}
else{
return jResponseFalse;
}
})
cb(aDrop);
}
Why not do it the recursive way? It's so simple. While loops won't work if you are using async functions.
if (response) {
return jResponse;
}
else {
return fnPickWinnerItem(chances,cb);
}
Dears ,
How can i run promises in nodejs sequentially , in the following example am looping through array of hours then for each fetched hour get result from the database , the issue here : am getting results but i want it sequentially same order that i got hours .
angular.forEach(SharedVar.getCategories(), function (h) {
t = h.split('-', 2);
t = t[0];
RESTApi.getAnswerdCallsByHour(t).then(function (answerdTotal) {
$scope.answerdCallsTotalByHour.push(answerdTotal);
var d = SharedVar.getDataS();
d[count] = answerdTotal;
SharedVar.setDataS(d);
count++;
});
});
Thanks ,
var promise = Promise.resolve(); // make an empty promise in the way you do it with your promise library
angular.forEach(SharedVar.getCategories(), function (h) {
promise.then(function() {
return RESTApi.getAnswerdCallsByHour(t).then(function (answerdTotal) {});
});
});
The way to do it sequently would be to do one Request and do the next request inside the promise.
I think the better approach by far is to extend your SharedVar.setDataS(d) function in a way, that it does not depend on getting the data sequentially. Like having a SharedVar.setDataS(d, index) and using the config var in your $http.get (or whatever) functioncall inside your RESTApi to promote that index all the way to the promise.
If your RESTApi looks like this:
var RESTApi = {
getAnswerdCallsByHour : function(hour) {
var url = "bla.com/myservice?hour=" + hour;
return $http.get(url).data;
}
// Some other Methods...
Then you need a way to pass something to "reorder" your Data when it arrives asynchronously, this could be a index you count up or in your case maybe the hour Variable:
var RESTApi = {
getAnswerdCallsByHour : function(hour) {
var url = "bla.com/myservice?hour=" + hour;
var config = [];
config.hour = hour;
return $http.get(url, config); // Return the promise not just data or a specific field
}
// Some other Methods...
Now when your promise is fullfiled you can access your "hour" Variable like so:
var d = SharedVar.getDataS();
d[promise.config.hour] = promise.data;
SharedVar.setDataS(d);
Now you know what piece of data correlates to which request and you do not need to recieve Data in order. The last piece only works properly when hours runs sequential from 0 to 23, if that isn't the case you need to:
var RESTApi = {
getAnswerdCallsByHour : function(hour, index) {
var url = "bla.com/myservice?hour=" + hour;
var config = [];
config.index = index;
return $http.get(url, config);
}
// Some other Methods...
...
...
var d = SharedVar.getDataS();
d[promise.config.index] = promise.data;
SharedVar.setDataS(d);
Safari's answer is how I typically handle this. (Sorry, I don't have enough rep to comment yet...) You were experiencing problems with it because the example provided does not capture and use the new promise in subsequent loops. See my comments on the slightly modified version here:
var promise = Promise.resolve();
angular.forEach(SharedVar.getCategories(), function (h) {
t = h.split('-', 2);
t = t[0];
// You must capture the new promise here; the next loop will wait
// for the promise returned from getAnswerdCallsByHour to resolve.
promise = promise.then(function() {
// Halt downstream promises until this returned promises finishes
return RESTApi.getAnswerdCallsByHour(t).then(function (answerdTotal) {
$scope.answerdCallsTotalByHour.push(answerdTotal);
var d = SharedVar.getDataS();
d[count] = answerdTotal;
SharedVar.setDataS(d);
count++;
});
});
});
What I'm trying to do is this, I have 2 users an attacker and a defender. I want the call hit() function until one of the runs out of Health, hit() should be called on turns, first attacker, then defender, then attacker and so on until one reaches 0 hp.
My idea was to do it with a while loop, with current code all I get is the console.log from hit(), an infinite loop. The data from hit() is returned correctly if it's not inside a loop ... I could simply just work in the while loop and not use the hit function but it would mean repeating a lot of code, since there will be a few things to consider before a hit actually happens.
If you have an alternative to the while loop I'm open to ideas, also I should mention I'm new at node so keep it as simple as possible please. Thank you.
This is the relevant part of the code:
var prepareAttack = function(attacker,defender) {
connectdb().done(function(connection) {
query(connection,'SELECT * FROM members WHERE name = ?', attacker).done(function(result) {
var attackerData = result[0][0]
query(connection,'SELECT * FROM members WHERE name = ?', defender).done(function(result) {
var defenderData = result[0][0]
var attackerHp = attackerData.hp
var defenderHp = defenderData.hp
while(attackerHp > 0 && defenderHp > 0) {
hit(attackerData,defenderData).done(function(result){
defenderHp = result;
console.log(defenderHp)
})
hit(defenderData, attackerData).done(function(result) {
attackerHp = result;
console.log(attackerHp)
})
}
})
})
})
}
var hit = function (attackerData, defenderData) { // simplified code just relevant parts inside.
console.log('hitting')
var defer = Q.defer()
var newHp = 0;
defer.resolve(newHp)
return defer.promise
}
I am using the source at http://blog.symprogress.com/2010/11/ribbon-insert-any-web-part-using-javascript/ to handle user web part button click event.
The function 'addWebPart()' calls a function 'SP.Ribbon.WebPartComponent.getWebPartAdder()' which is supposed to return adder instance but sometimes it returns undefined.
If I add a while loop to wait for the instance value to return correctly, the browser in my VM stalls for some time. When an instance is returned, the browser becomes responsive again. This only happens in some instances.
I am using SharePoint 2013 and the section of code I am referring to is:
addWebPart = function (wpCategory, wpTitle) {
var webPartAdder = SP.Ribbon.WebPartComponent.getWebPartAdder();
while (webPartAdder == undefined)
webPartAdder = SP.Ribbon.WebPartComponent.getWebPartAdder();
// ... Other stuff ...
}
How can this issue be resolved?
For anyone looking for an answer to this question, turns out you have to call 'LoadWPAdderOnDemand()' function then wait for the event '_spEventWebPartAdderReady'. Then query for 'window.WPAdder':
addWebPartDelayed = function (webPartAdder, wpCategory, wpTitle) {
var webPart = findWebPart(webPartAdder, wpCategory, wpTitle);
if (webPart) {
var zone = WPAdder._zones[0];
var wpid = WPAdder._createWebpartPlaceholderInRte();
WPAdder.addItemToPageByItemIdAndZoneId(webPart.id, zone.id, 0, wpid);
}
else
alert('ERROR: Web part not found! Please try again after sometime.');
},
addWebPart = function (wpCategory, wpTitle) {
var webPartAdder = window.WPAdder;
if (webPartAdder == undefined) {
LoadWPAdderOnDemand();
ExecuteOrDelayUntilEventNotified(
function () {
var webPartAdder = window.WPAdder;
addWebPartDelayed(webPartAdder, wpCategory, wpTitle);
},
"_spEventWebPartAdderReady");
}
else
addWebPartDelayed(webPartAdder, wpCategory, wpTitle);
};