Reputation: 229
I am new to JS and was learning promises. The code excerpt I want to show is this
promisedFunction.then(data=>console.log(data))
or simply
promisedFunction.then(console.log)
which is equivalent of the former code excerpt. The question is how is that possible to just use then(console.log)
instead of then(data=>console.log(data))
? Does it mean that we can omit the passed-from-promise data in thenable callback?
Upvotes: 2
Views: 271
Reputation: 29085
data=>console.log(data)
is a function that takes a parameter and calls a method with the passed in argument.
If you pass console.log
it will execute the same method and still pass the same argument.
In effect you are dropping the extra function call - slightly more abstractly, imagine this:
//some function `f`
const f = x => x + 1;
//different function `g` that just forwards the call to `f`:
const g = x => f(x);
console.log(g(41)); //42
The definition of g
is just a function that all it does is call f
. Which has exactly the same effect as the f
function. So, we can just re-write it as:
//some function `f`
const f = x => x + 1;
//different function `g` that just forwards the call to `f`:
const g = f;
console.log(g(41)); //42
and get exactly the same effect.
In Lambda Calculus, this removal of an essentially empty "wrapper function" is called Eta reduction.
Therefore, yes, both .then(data => console.log(data))
and .then(console.log)
do exactly the same, you're performing the same sort of conversion where you're taking out a dummy forwarding function.
However, that's not always an option. For example, if removing the forwarding function will end up calling the target with more parameters, you can get different behaviour. An infamous example is parseInt
when used in .map
:
const arrayOfString = ["1", "2", "3"];
const arrayOfIntegers1 = arrayOfString.map(parseInt);
const arrayOfIntegers2 = arrayOfString.map(x => parseInt(x));
console.log("arrayOfIntegers1", arrayOfIntegers1);
console.log("arrayOfIntegers2", arrayOfIntegers2);
The issue is that Array#map
calls the callback with three parameters - the item, the index, and the array. And parseInt
has an optional second parameter - if passed in, it changes how the number is parsed. So you get NaN
.
The easiest way to observe this is with console.log
:
const arrayOfString = ["1", "2", "3"];
console.log(" --- using just `console.log` as callback ---");
arrayOfString.map(console.log);
console.log(" --- using just `x => console.log(x)` as callback ---");
const arrayOfIntegers2 = arrayOfString.map(x => console.log(x));
So, dropping the intermediate function works as long as it has the same arity as what it will be called with and what the next function will be called with.
Upvotes: 3
Reputation: 50854
data => console.log(data)
is a function which takes in data
and then calls the function console.log
with data
as its argument. So, it's a function which gets given data
and then it gives that exact same data
argument to the console.log
function.
As you know console.log
is a function, so, you can place console.log
instead of your arrow function. This way, it will be called with the data
argument and any other arguments natively passed into .then()
's onFulfilled callback (in this case it only gets given the resolved value of the promise).
Take the following example below. bar
gets given "hello"
, which it gives to foo
, foo
accepts "hello"
and returns "hello"
back to where it was called, so, bar
ends up returning "hello"
:
const foo = x => x;
const bar = x => foo(x);
console.log(bar("hello"));
In the above example, bar
acts somewhat like a middle-man, as all it does is pass x
to foo
. This middle-step can be removed, by straight-up assigning bar
to foo
. This way, when we call bar()
, we are executing the code defined within the function foo
. This is the same idea that allows you to remove the need to explicitly defined your arrow function in .then()
:
const foo = x => x;
const bar = foo;
console.log(bar("hello"));
This style of coding is known as point-free style code and, in this case, is achieved by eta-reduction.
Upvotes: 1
Reputation: 18012
promisedFunction.then
expects a function to which will receive the data as a parameter.
in the case of data=>console.log(data)
is an array function equal to:
function(data) {
console.log(data);
}
and console.log
is also a function which prints in console what receives as a parameter.
That's why console.log works.
If you had:
var print = function(data) {
console.log(data);
}
promisedFunction.then(print)
would also work.
See this working example that will resolve after 2 secs:
const doSomething = function(){
return new Promise((resolve, reject) => {
let wait = setTimeout(() => {
resolve('Promise resolved!');
}, 2000)
})
};
var print = function(data) {
console.log(data);
}
doSomething().then(print)
Upvotes: 0
Reputation:
The return value of promise or the "resolved value" is the input to callback passed in then.
This behavior is not specific to promise but even [1,2,3].forEach(console.log)
behaves the same where the 3 arguments of forEach are passed to console log. Thus you get ,
1 0 Array(3) [ 1, 2, 3 ]
2 1 Array(3) [ 1, 2, 3 ]
3 2 Array(3) [ 1, 2, 3 ]
Upvotes: 0