Javascript function confused syntax - javascript

I am a little bit confused with the code below. It's obviously a two arrow function written in es6 code but I do not understand exactly some parts.
The 2nd parameter named done is an empty function that does nothing? Or it is executed with a simple return as the result from the second arrow anonymous function?
the XXXX.load is a promise function that returns some results. How the caller of the Index can get the results of the 2nd parameter done ie done(null, result) ?
What is the equivalent code in es5?
const Index = (name, done = () => {}) => (dispatch, getState) => {
return XXXX.load()
.then((result) => {
dispatch({type:OK});
done(null, result);
})
.catch((error) => {
dispatch({type:ERROR});
done(error);
});
};

Let's go one by one:
Index (name, done = () => {}) defines a default value for done in case none is provided when Index is called. This helps down to road to not do any checks in case done is null/undefined. You could also write it like this
const Index = (name, done) => (dispatch, getState) => {
if (!done) {
done = () => {}
}
}
The caller will just pass a function as the second argument when calling Index.
A general note: Index actually returns a function that will expect a dispatch and/or a getState param.

The 2nd parameter named done is an empty function that does nothing?
It's a parameter. It takes whatever value you give it.
The default value, which is assigned if the caller doesn't pass a second argument, is a function that does nothing. This lets it be called without throwing an undefined is not a function error or having an explicit test to see if it is a function or not.
How the caller of the Index can get the results of the 2nd parameter done ie done(null, result) ?
By passing its own function as the second argument.
What is the equivalent code in es5?
var Index = function(name, done) {
if (!done) done = function() {};
return function(dispatch, getState) {
return XXXX.load()
.then(function(result) {
dispatch({
type: OK
});
done(null, result);
})
.catch(function(error) {
dispatch({
type: ERROR
});
done(error);
});
}
};

The empty function is a default value for done. Default values prevents runtime crashes.
2 and 3 can be understood by seeing below code: (simply run it and see the consoles.
const DEFAULT_FUNCTION_VALUE = ()=> {};
const XXXX = {
load: function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve({data: 'from XXXX.load'});
},2000);
});
}
}
const Index = function(name='', done=DEFAULT_FUNCTION_VALUE) {
return function(dispatch, getState) {
return XXXX.load().then(function(result) {
console.log({result});
done(result);
}).catch(function(error) {
console.log(error);
});
}
}
function doneImplementation(data) {
console.log('Data from done- ', data);
}
Index('', doneImplementation)();

Related

Is the JavaScript promise handler determined by the order of its functions?

exports.userDidSignOut = functions.https.onCall((data) => {
const userId = data.userId;
const settingsUpdate = {
"fcmToken": null,
};
const promise = admin.firestore().collection("user-settings").doc(userId).update(settingsUpdate);
promise.then(
(_value) => {
return null;
},
(reason) => {
return console.log(reason);
}
);
});
I'm working with a database (Firestore) that returns a promise when data is updated. In this snippet above, I update the database with update() and it returns a value parameter on success and a reason parameter on failure. Because I can rename these parameters freely, how does the promise know which function is the success and which is the error? Is it purely based on the order they appear? And can I remove the value parameter entirely and will the promise know that's the function to call on success?
promise.then(
() => {
return null; // is removing the parameter of this function safe to do?
},
(reason) => {
return console.log(reason);
}
);

javascript function will not return value or object

Please help trying to get this function to return value back to my main process. currently everything shows in the console however if I return the object its blank or undefined
const GetSelectDeviceFromDB = () => {
db.all("SELECT * FROM device_list", function (err, rows) {
rows.forEach(function (row) {
console.log(row.device);
return row.device;
});
});
};
module.exports = { GetSelectDeviceFromDB };
OUPUTS:
console.log =. { device1, device2 }
return = undefined and if I add the return to the beginning of the sql statement I get {}
Since all() method is asynchronous and it is using a callback, you can turn your method into a method like this:
const GetSelectDeviceFromDB = () => new Promise((resolve, reject) => {
db.all('SELECT * FROM device_list', (err, rows) => {
if (err) {
reject(err);
}
const devices = rows.map((row) => row.device);
resolve(devices);
});
});
It will return a Promise, so you can call it like this:
GetSelectDeviceFromDB().then(devices => { ... })
Returning from forEach isn't a good idea, returning from another object's method (db.all in you case) isn't either. You need to return exactly in the first scope of the lambda function, somewhere outside of db.all(...). But in this case it's an async method, so you should make your whole function async or a Promise

How do I ensure I won't replace a content to an old response?

Good day for all,
I am doing a React course and I'd submited the code to the reviewer. He's returned me few comments and there is one comment I'm not being able to solve.
The comment is the following:
Check if (query === this.state.query) to ensure you are not going to replace the contents to an old response
And part of the code is the one below:
updateQuery = (query) => {
this.setState({
query: query
})
this.updateWantedBooks(query);
}
updateWantedBooks = (query) => {
if (query) {
BooksAPI.search(query).then((wantedBooks) => {
if (wantedBooks.error) {
this.setState({ wantedBooks: [] });
} else {
this.setState({ wantedBooks: wantedBooks });
}
})
} else {
this.setState({ wantedBooks: [] });
}
}
Anyone could help me what do am I suppose to do?
Regards.
Code reviewer is right, you don't really want to replace the response if user has entered the very same query.
You have to store somewhere what for user has searched recently:
this.setState({ wantedBooks: [], query });
In case of success response:
this.setState({ wantedBooks, query });
And then check it in case of further searches:
if (query && query !== this.state.query) {
// continue the search only if query is different that current
Instead of relying on an outer member which is open to abuse by other code, you can employ a factory function to more safely trap a member.
As you have discovered, trapping and testing query == this.state.query can be made to work but is arguably not the best solution available.
With a little thought, you can force each call of updateWantedBooks() automatically to reject the previous promise returned by the same function (if it has not already settled), such that any success callbacks chained to the previous promise don't fire its error path is taken.
This can be achieved with a reusable canceller utility that accepts two callbacks and exploits Promise.race(), as follows:
// reusable cancellation factory utility
function canceller(work, successCallback) {
var cancel;
return async function(...args) {
if (cancel) {
cancel(new Error('cancelled')); // cancel previous
}
return Promise.race([
work(...args),
new Promise((_, reject) => { cancel = reject }) // rejectable promise
]).then(successCallback);
};
};
Here's a demo ...
// reusable cancellation factory utility
function canceller(work, successCallback) {
var cancel;
return async function(...args) {
if (cancel) {
cancel(new Error('cancelled')); // cancel previous
}
return Promise.race([
work(...args),
new Promise((_, reject) => { cancel = reject })
]).then(successCallback);
};
};
// delay utility representing an asynchronous process
function delay(ms, val) {
return new Promise(resolve => {
setTimeout(resolve, ms, val);
});
};
function MySpace() {
// establish a canceller method with two callbacks
this.updateWantedBooks = canceller(
// work callback
async (query) => delay(500, query || { 'error': true }), // a contrived piece of work standing in for BooksAPI.search()
// success callback
(wantedBooks => this.setState(wantedBooks)) // this will execute only if work() wins the race against cancellation
);
this.setState = function(val) {
console.log('setState', val);
return val;
};
};
var mySpace = new MySpace();
mySpace.updateWantedBooks({'value':'XXX'}).then(result1 => { console.log('result', result1) }).catch(error => { console.log(error.message) }); // 'cancelled'
mySpace.updateWantedBooks(null).then(result2 => { console.log('result', result2) }).catch(error => { console.log(error.message) }); // 'cancelled'
mySpace.updateWantedBooks({'value':'ZZZ'}).then(result3 => { console.log('result', result3) }).catch(error => { console.log(error.message) }); // {'value':'ZZZ'} (unless something unexpected happened)
Note that canceller() doesn't attempt to abort the asynchronous process it initiates, rather it stymies the success path of the returned promise in favour of the error path.
I think reviewer's point is that response of Search API is asynchronous and result for "query 1" can arrive after user changed his mind and already requested search "query 2". So when response arrive - we need to check if we really interested in it:
updateQuery = query => {
this.setState({
query: query
wantedBooks: []
})
this.updateWantedBooks(query);
}
updateWantedBooks = query => {
if (query) {
BooksAPI.search(query).then((wantedBooks) => {
// if updateQuery("query1) and updateQuery("query2") called in a row
// then response for query1 can arrive after we requested query2
// => for some period of time we'll show incorrect search results
// so adding check if query still the same can help
if (query !== this.state.query) {
// outdated response
return;
} else if (wantedBooks.error) {
// query is okay, but server error in response
this.setState({
wantedBooks: []
})
} else {
// success response to requested query
this.setState({ wantedBooks });
}
})
}
}
Guys I´ve done some tests with your answers, but I realize that somehow the code was behavioring strangely.
So, I've seen in other part of the reviewer comments, a part which I hadn't had seen before do my answer here, the following comment:
Inside 'then' part of the promise check if(query === this.state.query) to ensure you are not going to replace the contents to an old response.
And this "Inside 'then'" has been beating in my brain.
So, I think I've arrived in a satisfatory code; sure, maybe it isn't the definite solution, that's why I want to show here for you and feel free to comment if I'd have to make some improvement. Here below I put the code:
updateQuery = (query) => {
this.setState({
query: query
})
this.updateWantedBooks(query);
}
updateWantedBooks = (query) => {
if (query) {
BooksAPI.search(query).then((wantedBooks) => {
if (wantedBooks.error) {
this.setState({ wantedBooks: [] });
} else if (query !== this.state.query) {
this.setState( { wantedBooks: [] });
} else {
this.setState({ wantedBooks: wantedBooks });
}
})
} else {
this.setState({ wantedBooks: [] });
}
}
Regards

Passing a callback function and creating an Observable from it

I cannot create a new Observable object out of the callback function, for example converting glob function to Observable stream:
const stream$ = fromCallback(() => glob('src/**/*.ts'));
const fromCallback = (cbWrapper) => {
const cb = cbWrapper();
const args = cb.arguments;
return Observable.create(observer => {
args.push((err, data) => {
if(err) {
observer.error(err);
} else {
observer.next(data);
}
observer.complete();
});
cb.call(null, args);
};
This is more or less what I want to do - create a fromCallback function which accepts my function in a wrapper, adds a new parameter which is a callback handler, and calls observer based on the results. But it doesn't work - the cbWrapper() returns always true for some reason.
What's wrong here? Is there a better solution to solve this?

Returning error as an array object value with promise

I'm using a scraping function to get some data from a bunch of urls listed inside an array. Here is the following function :
function getNbShares(urls) {
return Promise.map(urls, request).map((htmlOnePage, index) => {
const $ = cheerio.load(htmlOnePage),
share = $('.nb-shares').html();
return {
url: urls[index],
value: share
};
}).catch(function (urls, err) {
return {
url: urls[index],
value: err
};
});
}
It's working fine, however the error handling isn't. What I would like is that when I have an error (either because the page doesn't load or if the DOM selector is wrong) the map function/request keep doing is job and it returns me the error (or null) as a value attached to the url in the final array object.
I think you just want to do that handling a bit earlier, within the mapping function; and I think you can avoid having two separate mapping operations; see comments:
function getNbShares(urls) {
return Promise.map(
urls,
url => request(url)
.then(htmlOnePage => { // Success, so we parse
const $ = cheerio.load(htmlOnePage), // the result and return
value = $('.nb-shares').html(); // it as an object with
return { url, value }; // `url` and `value` props
})
.catch(error => ({url, error})) // Error, so we return an
// object with `url` and
// `error` props
}
);
}
(I've assumed you're using ES2015+, as you were using arrow functions.)
I might opt to factor part of that out:
function getNbSharesFromHTML(html) {
const $ = cheerio.load(html);
return $('.nb-shares').html();
}
function getNbShares(urls) {
return Promise.map(
urls,
url => request(url)
.then(htmlOnePage => ({url, value: getNbSharesFromHTML(htmlOnePage)))
.catch(error => ({url, error}))
}
);
}
Possibly even smaller pieces:
function getNbSharesFromHTML(html) {
const $ = cheerio.load(html);
return $('.nb-shares').html();
}
function getNbSharesFromURL(url) {
return request(url)
.then(htmlOnePage => ({url, value: getNbSharesFromHTML(htmlOnePage)))
.catch(error => ({url, error}));
}
function getNbShares(urls) {
return Promise.map(urls, getNbSharesFromURL);
}

Categories

Resources