This question already has answers here:
Curly Brackets in Arrow Functions
(3 answers)
Arrow function without curly braces
(9 answers)
Closed 1 year ago.
I am a novice in javascript and I've been learning about promises, recently I started working in some simple list that is retrieved with a random delay (setTimeout), a classical I think. After trying and doing some research I found I post that helped me a lot, and it works fine, but after reviewing what that post suggest against I had done before I noticed that the difference are two brackets...I've been reading and trying to understand why that brackets make such a difference (both options are functional) but I don't get it.
Could some one explain what's the difference? The brackets I mentioned are in function loadIng(), lines 5 and 12, the open bracket in first line and the closing one in the second.
{
new Promise(resolve => {
...
})
}
If I run the code with the brackets it runs synchronously, but if I run it without the brackets it runs asynchronously...I really don't get it.
function loadIngs() {
p = Promise.resolve();
for (let [k, v] of someArray) {
p = p.then(() =>
{new Promise(resolve => { //this
delay = Math.random() * 2000;
console.log(`${k}:${v} comes delayed for ${delay}`)
setTimeout(() => {
console.log("executes some function")
resolve();
}, delay);
})} //this
);
}
}
The difference here has to do with the automatic return value of an arrow function that does not use brackets around a single statement function body.
If you're talking about the new Promise() in the loadIngs() function, here:
function loadIngs() {
p = Promise.resolve();
for (let [k, v] of ings) {
p = p.then(() =>
{new Promise(resolve => {
delay = Math.random() * 2000;
console.log(`${k} comes delayed for ${delay}`)
setTimeout(() => {
setIng(k, v);
resolve();
}, delay);
})}
);
}
}
then the brackets around that new Promise() there are somewhat optional.
A single statement arrow function body may either be declared with or without brackets. Here's a simple example:
setTimeout(() => console.log("hi"), 100)
setTimeout(() => { console.log("hi") }, 100)
These are nearly the same thing. Since the function body is a single statement console.log("hi"), the arrow function body may stand alone or may be surrounded with brackets. Either is fine and generates the same execute EXCEPT for the return value. If you use brackets, then you need a return statement if there's a specific return value you want. Without the brackets the value of the single statement automatically becomes your return value of that arrow function.
This return value makes a difference in your promise example. So, for the p.then(() => ...) structure in the loadIngs() function. It can either be:
p.then(() => { return new Promise(...) })
or it can be:
p.then(() => new Promise(...) )
These two execute identically. But, notice that this is NOT exactly the same as shown in your code. I added a return in front of the new Promise(). When you remove the return, then this:
p.then(() => { new Promise(...) })
Has no return value from the arrow function. That means that while you create a new promise, you don't return it from the .then() handler and thus it is not linked into the parent promise chain and you get multiple independent promise chains.
This WILL create an execution difference and is probably responsible for what you say when you say one "runs asynchronously". That isn't exactly how I would describe it, but it does create a difference in the timing of when things run because in one case you have a single linked promise chain and in the other case you have two separate, independent promise chains.
Related
I'm trying to write a function composition that partially applies an argument at each step and ends up calling a curried two-argument function.
There is a set of example functions to compose. I removed the calculations that there are supposed to do as they are not relevant to the problem but let's assume that every argument is required.
const getDayLimit = () => {
return 10
}
const getIpCount = ip => dayLimit => {
return 99
}
const getIp = (deviceId, headerIp) => {
// TODO: use Result monad to handle errors
if (!deviceId && !headerIp) {
throw new Error('Ip not provided')
}
return deviceId || headerIp
}
And the composition attempt:
const validateIp = R.compose(
f => f(getDayLimit()),
getIpCount,
getIp
)
validateIp(1, 2)
In the first step, getIp received two values and based on them returns an ip that is then partially applied to getIpCount, now the composition return a function that expects the dayLimit argument that needs to be computed first.
The plain way of doing this could be: f => f(getAccountLimit()).
I'd like to remove such function creation f => f... and pass it point-free.
Here's a helper function that solves this but is not handling all cases such as passing arguments to the result function:
const applyResult = result => f => R.compose(f, result)()
then I could do:
const result = R.compose(
applyResult(getDayLimit),
getIpCount,
getIp
)
It seems too hacky for me and not substantial for my further use. I'd rather avoid writing my own helper function for this kind of problem.
Is there a functional way of computing arguments before partially applying them to a function? It seems to be a pretty common case in my mind, though perhaps I'm not thinking about the problem correctly.
Is my thinking incorrect about this problem and function composition?
What is a good approach to handling such a case with a function with two parameters in a composition?
Can this case of partially applying function arguments with each step be handled in a function composition?
Thank you!
I think I would use a continuation which, as I understand it, represents a computation that has been interrupted:
const cont = x => f => f(x);
With a continuation, you get x before f. Instead of doing f(x) you do cont(x)(f) which behind the scene just does f(x) for you.
At the time of composing the functions together you already know the value of x which is getDayLimit(), you just don't know the value of f yet which is known only when result is applied to the first two initial parameters.
So here's what I'd do:
const result = R.compose( cont(getDayLimit())
, getIpCount
, getIp);
Is there a functional way of computing arguments before partially applying them to a function?
I would simply note that you apply a function to a value (not the other way round)
This question already has an answer here:
How to chain and share prior results with Promises [duplicate]
(1 answer)
Closed 6 years ago.
Is there a better way to do this?
let foo;
return functionA().then(result => {
foo = result;
return functionB();
}).then(bar => {
return functionC(foo, bar);
});
Notice that the result of functionA is required input to functionC. Using a variable outside the promise scope works fine, but it feels kinda icky. Is there a clean idiomatic way to do this?
Please note that I do not have the opportunity to change the API of any of the functions I am calling.
You could try using Promise.all() which you can pass an array of promises and it provides an array of responses within the then() callback when all promises passed in have resolved. You can access those array values to pass into functionC:
Promise.all([functionA, functionB]).then(values => functionC(values[0], values[1]));
Might be a little cleaner (without nesting) as it doesn't look like the response from functionA needs to be passed into functionB.
Otherwise, nesting would look like:
return functionA().then(foo => {
return functionB().then(bar => {
return functionC(foo, bar);
});
});
One option is, as Alexander Staroselsky writes, to use Promise.all(functionA(), functionB()). This runs the two functions simultaneously. If that's what you want to happen, you can use that answer. If, however, you want them to happen one after the other and then also be able to pass the result onto another handler, you can do this:
function functionA() {
return new Promise(resolve => resolve(1));
}
function functionB() {
return new Promise(resolve => resolve(2));
}
function functionC(first, second) {
return first + second;
}
functionA()
.then(result => Promise.all([result, functionB()]))
.then(function([first, second]) {
return functionC(first, second);
})
.then(result => {
console.log(result);
});
The functions are obviously simplified -- but the lovely thing about Promises is that that doesn't matter: we don't care how complex they are or how long they take. Yay Promises!
The clever thing is that Promise.all doesn't mind if the values you pass are not Promises. If they are any other value, they are treated as a Promise that is resolved immediately. (In the same way that you can do Promise.resolve(42).then(...).) So we can do Promise.all([result, functionB()]). This says "give me a Promise that is resolved when you have a final value for both result and functionB() and pass both values on". That is immediately in the case of result and at some unspecified time in the case of functionB.
The returned values are then passed as an array to the next then function.
.then(function([first, second]) {
return functionC(first, second);
})
This then receives the values as an array (see the use of destructuring in the parameter list) and sends those values on to functionC. We then do one last then function to show the result.
I'm currently studying Electron in Action. I'm learning JavaScript on-the-go and this didn't come up in google so I'd thought I'd ask it in here. Imagine we have this code:
newLinkForm.addEventListener('submit', (event) => {
event.preventDefault();
const url = newLinkUrl.value;
fetch(url)
.then(response => response.text())
.then(parseResponse)
.then(findTitle)
.then(title => storeLink(title, url))
.then(clearForm);
});
in the first, and the fourth ring of the chain, we've gave a name to the return value of the zeroth, and the third function. But what if there are more than one return values? Do we create a list? Can we call two functions in a promise chain as in:
then(returnvalue1=>funct1, returnvalue2=>funct2)
Can we do that? Thanks for the response.
A promise only has a single resolved value, so a .then() handler is only ever passed a single argument.
If you want to resolve a promise with multiple values, then you would typically wrap them in an array or an object and the single resolved value would be the array or the object.
You could use destructuring to then easily reference the multiple values wrapped in the object or array.
Example:
Promise.resolve([1,2]).then(result => {
console.log(result); // logs [1,2]
return result; // pass the array on to the next step
}).then(([a, b]) => { // use destructuring to get the two items out of the array
console.log(a);
console.log(b);
});
What you proposed like this:
.then(returnvalue1=>funct1, returnvalue2=>funct2)
is something entirely different. Here you're passing two functions to a .then() as in .then(f1, f2) (or that looks like what you're trying to do). When you pass a second function to .then() that second function is a reject handler (like a .catch() handler) and it's only called if the promise rejects and the argument would be the rejection reason.
Second then argument is reserved for error handler, then(returnvalue1=>funct1, returnvalue2=>funct2) isn't a correct way ti handle return values.
then callback receives the only one return value as a parameter, a value that previous then callback returns.
In case values from different then need to be used together, they should be either passed through entire promise chain as array or object value and destructured:
promise
.then(foo => {
const bar = 'bar';
return [foo, bar];
})
.then(([foo, bar]) => {
// can access both foo and bar
})
Or then should be nested to have access to the scope where necessary value is available:
promise
.then(foo => {
const bar = 'bar';
return Promise.resolve(bar);
.then(bar => {
// can access both foo and bar
})
})
This is one of the problems that async..await solves.
I know this example is quite contrived but I am still curious wether or not this can be considered a pure function:
const addAsync = (x, y) => new Promise((resolve, reject) => {
setTimeout(
() => resolve(x + y),
Math.random() * 1000
);
});
Every call to this function returns a Promise that resolves to the sum of the two arguments. The promise resolves after a random amount of time between 0 and 1 seconds.
For all intends and purposes, this seems to be perfectly pure, meaning that I can treat this function in tests or in my code as a pure function (a, b) -> Promise(a + b). However, since we are using Math.random(), we cannot transform this function into a lookup table and back without losing functionality (we lose the delay). So can this considered to be pure or not?
I believe it can be consider as a pure function. A pure function is defined as a function where the return value is only determined by its input values, without observable side effects.
In this case the output is only determined by its input and it doesn't produce any side effects. The fact that it takes different amount of time to compute the result should not have an effect on its pureness.
But i would warn that i am not a functional programming expert and i may be wrong
Let's clarify the term pure first. Purity means referential transparency, ie. one can replace an expression with its evaluated result without altering the behavior of the program. Here is an action that returns a promise. To visualize the computation I perform logging as a side effect:
const addAsync = (x, y) => new Promise((r, e) => {
setTimeout(
z => (console.log(z), r(z)),
Math.random() * 1000,
x + y
);
});
console.log("before");
addAsync(2, 3);
console.log("after");
// logs
"before"
"after"
5
Next I substitute the expressionaddAsync(2, 3) with its result, which is a fulfilled Promise containing 5. Since there is no Promise literal in Javascript, I represent an already settled promise with Promise.resolve:
console.log("before");
Promise.resolve(console.log(5), 5);
console.log("after");
// logs
"before"
5
"after"
Looking at the code there seems to be no difference. The expression addAsync(2, 3) yields a settled promise (kind of like Promise(5)).
Promise.resolve(console.log(5), 5) on the other hand represents this very settled promise. But by observing the console.log side effects we can see that the evaluation order has changed, that is a function that returns a promise actually alters the behavior of a program. Hence such a function is impure.
No.
I would argue that the state the returned Promise is in, is unknown to us, just like the life of the cat of Schroedinger. The Promise is either resolved or rejected or pending, but we cannot predict when it is in what state. A snippet that outlines this:
let a = 0;
addAsync(1,2).then(res => a += res).then(console.log);
addAsync(0, 1).then(res => a += res).then(console.log);
If addAsync would be pure, it would always log the same.
Simple answer is NO. But I offer a simple way to push the impurity elsewhere
In the pure part of your code
const incRandomDelay = addAsync.bind(null,1)
Now somewhere in the effects part of your code
incRandomDelay(10).then( sum => writeToFile(sum) )
Besides lazy execution, are Tasks and Promises pretty much the same thing?
When I refer to a task, I refer to a class that is in its most basic behavior like the following:
class Task {
constructor(then) {
this.then = then;
}
map(mapper) {
return new Task((resolve, reject) => this.then(
x => resolve(mapper(x)),
reject
))
}
flatMap(mapper) {
return new Task((resolve, reject) => this.then(
x => mapper(x).then(resolve, reject),
reject
))
}
}
What type of (class?) is a task/promise? I'm learning about functional programming approaches, but I don't think I've gotten to this type yet. Is it a type of monad?
Yes, the key thing is a monadic bind, or a flatMap in your case that has the signature:
Task A -> A -> Task B -> Task B
With promises - that's the then method that:
Promise A -> (A -> Promise B) -> Promise B
this onFulfilled return value
In fact, both are instances of the Continuation Monad. Lots of other things (like Rx streams) are instances of the continuation monad.
Promises in JavaScript however are specced with a slightly different (and uglier, for arguably practical reasons) signature with it being possible to also return a plain value from then, and there are exception semantics involved.
There was a push for more "monadic" promises back in 2013 when they were specced, but it failed. The current promises in JavaScript aren't really "monad"s per-se.
A.promises are one refactoring step further than callback.just that.
if you have a function
const f = x => x * x ;
1) Use Callback and remove return type
you can pass a callback and remove the return type. This the famous Continuation-passing style
const f1 = (x,callback)=>callback(x*x);
What if we curry the action and return it as a result ?! we could do this :
const squareCont = (x)=>callback=>callback(x*x);
if you look at this for a long time and rename callback to resolve you will see that this is actually a promise.
//i rewrited it to make it clearer
var squareCont = function(x){
return function (resolve){return resolve (x*x);}
}
[Side Note : we could make it into a Promise if we enclose the callback into an object that exposes a then function like that :
const squarePromise = (x)=>({then:callback=>callback(x*x)});
squarePromise(2).then(r=>console.log(r))
check the fiddle here]
B.Task is the Coninuation Co-Monad . Because i cannot summarize it here you can read in more detail here : Promises & Continuation Monad in JavaScript
and here
Async/await a.k.a Continuation Co- Monad in JavaScript