How to combine asynchronous calls with synchronous in javascript - javascript

I'm kind of beginning to learn javascript and have a question about combining synchronous and asynchronous calls to functions. This will be just a theoric problem, but I hope it transmits the idea.
Let's suppose we have javascript program that decides how many bananas and oranges I need to buy.
console.log('buy %d bananas and %d oranges', bananas, oranges)
Now, I can decide how many bananas I can buy, but I need to ask my wife how many oranges she wants, so I text her. (I can write an async function to represent this).
This would be my immediate approach:
var bananas = 10;
var oranges = 0;
textWife('askAboutOranges',function(number){ oranges = number; }
console.log('buy %d bananas and %d oranges', bananas, oranges)
But to me this doesn't make sense, because I have to wait for my wife to reply, so I probably won't have the number of oranges in time.
So I can change my program to:
var bananas = 10;
var oranges = 0;
textWife('askAboutOranges',function(number){
oranges = number;
console.log('buy %d bananas and %d oranges', bananas, oranges);
}
But I don't like this because now I have the logic of deciding what to buy including the bananas, inside the response from my wife. What if I decide I don't want oranges, do I have to do something like this:
var bananas = 10;
var oranges = 0;
if (wantOranges)
{
textWife('askAboutOranges',function(number){
oranges = number;
console.log('buy %d bananas and %d oranges', bananas, oranges);
}
}
else
console.log('buy %d bananas and %d oranges', bananas, oranges);
So my question is, can anyone explain me what's the best/right way to do something like this?

jQuery Deferred is a great tool to have in your belt. I might do something like this to separate concerns:
function decideHowManyBananas() {
return 10;
}
function decideHowManyOranges() {
var deferred = $.Deferred();
if (wantOranges) {
textWife('askAboutOranges', function(number) {
deferred.resolve(number);
});
} else {
deferred.resolve(0);
}
return deferred.promise();
}
$.when(decideHowManyBananas(), decideHowManyOranges()).done(function(bananas, oranges) {
console.log('buy %d bananas and %d oranges', bananas, oranges);
});

There's no right/best way - it always depends. Modern Javascript libraries use concepts like Deferreds and Promises to synchronize between multiple async calls, sync calls and immediate data. Using jquery, your code might be written as:
$.when({bananas:10, oranges:1}, textWife('askAboutOranges')).done(function(myList, herList) {
buyBananas(myList.bananas);
buyOranges(myList.oranges + herList.oranges);
});
See http://api.jquery.com/category/deferred-object/ for more information.
And this is how to create Deferred objects in your code, in an elegant way:
function decideHowManyOranges() {
if (!wantOranges)
return 0;
return $.Deferred(function(d) {
textWife('askAboutOranges', function(number) {
d.resolve(number);
})
})
}
numOfBananas = 10
$.when(numOfBananas, decideHowManyOranges()).done(function(bananas, oranges) {
console.log('buy %d bananas and %d oranges', bananas, oranges);
});

With Promises
// setup
var bananas = 4
var wantOranges = true
function textWife() { return new Promise((resolve, reject) => setTimeout(() => resolve(8), 1000)) }
// execution
Promise.all([
bananas,
wantOranges ? textWife() : 0 // ternary is necessary here because boolean logs as `NaN`
]).then(([bananas, oranges]) => console.log('buy %d bananas and %d oranges', bananas, oranges))
Note: I am using ..
Promises
Destructuring assignment where var [bananas, oranges] = [4, 8] is same as var bananas = 4, oranges = 8.
Arrow functions () => {}

Prepare a function and use it in both cases to remove code duplication:
var bananas = 10;
var oranges = 0;
function buyStuff() {
console.log('buy %d bananas and %d oranges', bananas, oranges);
}
if (wantOranges)
textWife('askAboutOranges',function(number){
oranges = number;
buyStuff();
})
else
buyStuff();

In your first example, you state that the answer to the question "how many bananas and oranges should I buy?" is dependent on both information you possess, i.e. the number of needed bananas, as well as information you do not possess, the number of needed oranges, so you cannot answer it without first acquiring the missing information.
You then refactor your code to defer answering your question till you possess the missing information which is the typical approach to solving this kind of dependency.
You then state that this doesn't satisfy you because you may not wish to purchase any oranges at all. This is a new requirement and so invalidates your original question, changing it to "how many bananas should I buy?"
By removing the requirement for the missing information, you change the question and so need to special case your problem into two questions.
The final code example you provide does this by first deciding if you need to purchase both bananas and oranges or just oranges, which is indeed the most straightforward way of solving your problem.

Related

trying to get the most used word using regex

I am trying to get 10 most frequent word in the sentence below, I need to use regular expression.
let paragraph = `I love teaching. If you do not love teaching what else can you love. I love Python if you do not love something which can give you all the capabilities to develop an application what else can you love.
I want an output like this
{word:'love', count:6},
{word:'you', count:5},
{word:'can', count:3},
{word:'what', count:2},
{word:'teaching', count:2},
{word:'not', count:2},
{word:'else', count:2},
{word:'do', count:2},
{word:'I', count:2},
{word:'which', count:1},
{word:'to', count:1},
{word:'the', count:1},
{word:'something', count:1},
{word:'if', count:1},
{word:'give', count:1},
{word:'develop',count:1},
{word:'capabilities',count:1},
{word:'application', count:1},
{word:'an',count:1},
{word:'all',count:1},
{word:'Python',count:1},
{word:'If',count:1}]```
This is a solution without regexp, but maybe it is also worth looking at?
const paragraph = `I love teaching. If you do not love teaching what else can you love. I love Python if you do not love something which can give you all the capabilities to develop an application what else can you love.`;
let res=Object.entries(
paragraph.toLowerCase()
.split(/[ .,;-]+/)
.reduce((a,c)=>(a[c]=(a[c]||0)+1,a), {})
).map(([k,v])=>({word:k,count:v})).sort((a,b)=>b.count-a.count)
console.log(res.slice(0,10)) // only get the 10 most frequent words
I have something a bit messy but it uses regex and displays top 10 of the highest occuring results which is what you asked for.
Test it and let me know if it works for you.
let paragraph = "I love teaching. If you do not love teaching what else can you love. I love Python if you do not love something which can give you all the capabilities to develop an application what else can you love.";
//remove periods, because teaching and teaching. will appear as different results set
paragraph = paragraph.split(".").join("");
//results array where results will be stored
var results = []
//separate each string from the paragraph
paragraph.split(" ").forEach((word) => {
const wordCount = paragraph.match(new RegExp(word,"g")).length
//concatenate the word to its occurence:: e.g I:3 ::meaning I has appeared 3 times
const res = word + " : " + wordCount;
//check if the word has been added to results
if(!results.includes(res)){
//if not, push
results.push(res)
}
})
function sortResultsByOccurences(resArray) {
//we use a sort function to sort our results into order: highest occurence to lowest
resArray.sort(function(a, b) {
///\D/g is regex that removes anything that's not a digit, so that we can sort by occurences instead of letters as well
return(parseInt(b.replace(/\D/g, ""), 10) -
parseInt(a.replace(/\D/g, ""), 10));
});
//10 means we are using a decimal number system
return(resArray);
}
//reassign results as sorted
results = sortResultsByOccurences(results);
for(let i = 0; i < 10; i++){//for loop is used to display top 10
console.log(results[i])
}
To get all words in a sentence use regular expressions:
/(\w+)(?=\s)/g.
If you use this in your input string then you get all words without the word which end with full-stop(.) i.e don't match the word "love.".
paragraph.match(/(\w+)(?=(\s|\.|\,|\;|\?))/gi)
So, in this case we have to modify the regex as:
/(\w+)(?=(\s|\.))/g.
Similarly, add the other special(,; ...) character which is end with some word.
This is your solution (please add the other special character if it's required).
let paragraph = `I love teaching. If you do not love teaching what else can you love. I love Python if you do not love something which can give you all the capabilities to develop an application what else can you love.`;
let objArr = [];
[...new Set(paragraph.match(/(\w+)(?=(\s|\.|\,|\;|\?))/gi))].forEach(ele => {
objArr.push({
'word': ele,
'count': paragraph.match(new RegExp(ele+'(?=(\\s|\\.|\\,|\\;|\\?))', 'gi'))?.length
})
});
objArr.sort((x,y) => y.count - x.count);

Using Arithmetic operators in parameters of a Function

I tried to do it but didn't work
I want to achieve something like this:
function clubMember(clubName, women + men, women, men) {
const club = `${clubName} club has ${women + men} members including ${women} Women and ${men} Men`
return club
}
The answer is: no, you can't put arithmetic operators as a parameter.
As far as I know, there are no languages that gives you ability to calculate as a parameter.
However, you could do something like this if you wish:
function clubMember(clubName, total, women, men) {
const club = `${clubName} club has ${total} members including ${women} Women and ${men} Men`;
return club;
}
clubMember(club, women+men, women, men);

I am trying to scrape amazon, and stop at a specific number

So this is my code
if (body.included != null && body.included.length > 0) {
let genres = '';
for(let i = 0; i < body.included.length; i++) {
genres += body.included[i].attributes.title;
if(i != body.included.length - 1) {genres += ', ';}
}
embed.addField('GENRES', [`${genres}`,], true);
}
this is the results whenever i search anything with this it gives me this:
Comedy, Kids, Fantasy, Fantasy World, Erotic Torture, Loli, Nudity, Bdsm, Bondage, Sex, Past, Plot Continuity, Violence, Military, Mecha, Historical, Action, Romance, Science Fiction, World War II, Japan, Asia, Piloted Robot, Alternative Past, Steampunk, Gunfights, Alien, War, Robot, Adventure, Space Travel, Cyborg, Crime, Other Planet, Humanoid Alien, Future, Space, Contemporary Fantasy, Vampire, Slice of Life, Detective, Bounty Hunter, Magic, Present, Demon, Super Power, Drama, Anime Influenced, Earth, Love Polygon, Angst, High School, School Life
Has this a example because other types searches comes with 1 or 2 or decent amount of genres where it doesn't have like 40 of them
like this one
Ninja, Fantasy World, Adventure, Action, Comedy, Martial Arts, Super Power, Romance, Disaster, Shounen, Love Polygon, Angst, Plot Continuity, Parallel Universe, Fantasy
So what i need help is how do i make it stop in a certain number where it wont give me 40 of them instead 10 or less
You could change the loop condition but still need to watch out for the length of the body.included array for cases where it has fewer than 10 elements. Try the following:
const MAX_GENRES = 10;
if (body.included && body.included.length) {
const max = Math.min(MAX_GENRES, body.included.length);
const genres = [];
let i = 0;
while (i < max) {
genres.push(body.included[i].attributes.title);
i += 1;
}
embed.addField('GENRES', [genres.join(',')], true);
}
This should achieve what you're after. I don't know the signature for embed.addField() but are you certain that the second argument should be a single-element array containing a string? Could be but seems weird. If the function calls for an array of strings use:
embed.addField('GENRES', genres, true);

ManyChat, Zapir and JavaScript; how to send out different messages per the end result

I am trying to create questionnaire (15 questions)in my Messenger with the two possible answers Yes and No. Each answer has value (Yes..3) and (No..1). I create Zap where I calculate number like result. I create Java script code by Zapier like next step and here my knowledge is finished. I code to calculate number and like next step sending the message back with answer like number.
What I want from javascript code by Zapier is to calculate answers and based on the results send the answer to Subscriber who answer the Questionnaire.
The answer message according to the scoring answers should be following:
<26
"messege"
26-35
"messege"
>35
"messege"
Here it is how I made until now (sorry but answers are in Slovene language...not important):
return {
calculatednumber: Number(inputData.q1) + Number(inputData.q2) + Number(inputData.q3) + Number(inputData.q4) + Number(inputData.q5) + Number(inputData.q6) + Number(inputData.q7) + Number(inputData.q8) + Number(inputData.q9) + Number(inputData.q10) + Number(inputData.q11) + Number(inputData.q12) + Number(inputData.q13) + Number(inputData.q14) + Number(inputData.q15)
}
if (calculatednumber ==='<25') {
return []; //"Videti je, da so vaše prehranske navade ustrezne. Za izboljšanje priporočamo jemanje multivitaminskih/mineralnih tablet!"
}
if (calculatednumber ==='26,27,28,29,30,31,32,33,34,35') {
return []; //"Multivitaminski/mineralni dodatek k prehrani bo vašemu telesu pomagal ohraniti esencialna hranila, ki jih potrebuje, skupaj z drugimi označenimi dodatki!"
}
if (calculatednumber ==='>36') {
return []; //"Vnos multivitaminov/mineralov bi vam zagotovo koristil. Z bolj uravnoteženo prehrano in dodatkom multivitaminov/mineralov pa bi potrebovali še vnos drugih vitaminov/mineralov!"
};
Thank you for helping me.
You're on the right track! Some pointers:
You'll only ever call one return function, so you don't want to use it for the variable at the top.
You don't need to nest the variable inside an object; it can just be a number
the calculatedNumber variable will never be equal to "<25" because that's a string with a character in it, so your logic branches don't work.
Try this instead:
let calculatedNumber = Number(inputData.q1) + Number(inputData.q2) // + ...
if (calculatedNumber < 25) {
return {message: 'Small Message'} // it's important to return an object
} else if (calculatedNumber > 36) {
return {message: 'Large Message'}
} else {
// everything inbetween 25 and 36
return {message: 'Medium Message'}
}
Anyway, I'd recommend reading through https://learnxinyminutes.com/docs/javascript/ to get a better handle on some of the syntax fundamentals.

(JavaScript) Random Text Output - Suggestions?

So what I have is http://garrettstelly.com which spits out one of twenty terms at startup. The code is very heavy, and I'm fine with that.
I plan on making a website to spit out a name at random, the problem is that I can have an endless amount of names. For the js that I'm using currently, I'm using a random roll and even portions between 0 and 1 to read the names. The problem with that is that I can't ever add just one phrase, I'll have to add a chunk all at once for the probabilities to be even.
How can I make a script with an endless amount of possibilities to be added one at a time?
here's the javascript for garrettstelly.com:
var roll = Math.random()
if (roll<0.05)
{document.write('Bro-Heem');}
else if (roll<0.10)
{document.write('I am too white for my own good');}
else if (roll<0.15)
{document.write('I love the way you paste those stickers.');}
else if (roll<0.20)
{document.write('You probably were not just thinking about Wichita');}
else if (roll<0.25)
{document.write('Yummy, Adhesive!');}
else if (roll<0.30)
{document.write('Rolex');}
else if (roll<0.35)
{document.write('There is a 5% chance that you will see this when you first visit this website.');}
else if (roll<0.40)
{document.write('Making Money.<br>Choppas How We Do Today.');}
else if (roll<0.45)
{document.write('45, get your bills roll em high.');}
else if (roll<0.50)
{document.write('I WILL teach you how to fish');}
else if (roll<0.55)
{document.write('I am a gangsta.');}
else if (roll<0.60)
{document.write('Please get out of my website');}
else if (roll<0.65)
{document.write('derriere');}
else if (roll<0.70)
{document.write('I think YOU are a Q T PIE');}
else if (roll<0.75)
{document.write('X=Fries');}
else if (roll<0.80)
{document.write("Idle hands are the Devil's playground.<br>The Devil is smaller than hands.");}
else if (roll<0.85)
{document.write('I am about to be late for class');}
else if (roll<0.90)
{document.write('"Hipster"');}
else if (roll<0.95)
{document.write('I am late for class');}
else
{document.write('Please refrain from drinking the water located within the wishing well, thank you.');}
Store the possibilities in an array and get a random element of the array:
Demo
function getRandomName()
{
var names = [
'John',
'Sue',
'Bob',
'Sandeep'
];
return names[Math.floor(Math.random() * names.length)];
}
document.write( getRandomName() );
You should put all the things you want spit out into an array. For example:
var arr = [
'Bro-Heem',
'I am too white for my own good',
// other entries...
'Please refrain from drinking the water located within the wishing well, thank you.'
];
Then your roll should still be Math.random() but multiplied by the length of the array:
var roll = (Math.floor(Math.random()) * arr.length);
Then write your result with the appropriate array index, in your case by using document.write (though there may be better ways):
document.write(arr[roll]);
Now you can add to your array as much as you like.
I would use an array:
var outputTextArr = ['text 1', 'text 2', 'text 3', 'text 4', 'more text', 'some text'];
Then randomly target the items in the array:
function randomRange(from, to){
return Math.floor(Math.random() * (to - from + 1) + from);
}
var outputText = outputTextArr[randomRange(0, outputTextArr.length - 1)];//var output text will have a random item
Something like this should work
var sentences =
[
"I am too white for my own good",
"I love the way you paste those stickers.",
"You probably were not just thinking about Wichita"
// Add more sentences if you want to
];
var index = Math.floor(Math.random() * sentences.length);
alert(sentences[index]); // This will be your random value
CodePen example.

Categories