I'm just trying to understand the benefits of this:
const populateUsers = done => {
User.remove({}).then(async () => {
const userOne = new User(users[0]).save();
const userTwo = new User(users[1]).save();
const usersProm = await Promise.all([userOne, userTwo]).then(() => done());
return usersProm;
});
};
over this:
const populateUsers = done => {
User.remove({})
.then(() => {
const userOne = new User(users[0]).save();
const userTwo = new User(users[1]).save();
return Promise.all([userOne, userTwo]);
})
.then(() => done());
};
I came to this problem because eslint suggested my to use async in this function, and I remember the concept, make it work in my app, but I'm not sure why should I use this instead of the original way
Your original code was totally fine.
No, there is no benefit in using the code from your first snippet. You should avoid mixing await and .then(…) syntax! To use async/await, you'd make the whole function async, not the then callback:
async function populateUsers(done) {
await User.remove({})
const userOne = new User(users[0]).save();
const userTwo = new User(users[1]).save();
await Promise.all([userOne, userTwo]);
return done();
}
(Probably you would also remove that done callback - the function already returns a promise)
Your first version does not go all the way. Do this:
const populateUsers = done => {
User.remove({}).then(async () => {
const userOne = new User(users[0]).save();
const userTwo = new User(users[1]).save();
await Promise.all([userOne, userTwo]);
const usersProm = await done();
return usersProm;
});
};
There is no difference, it is just that code without these then callbacks is somewhat easier to read.
You might even apply it to the outer function:
const populateUsers = async () => {
await User.remove({});
const userOne = new User(users[0]).save();
const userTwo = new User(users[1]).save();
await Promise.all([userOne, userTwo]);
const usersProm = await done();
return usersProm;
};
Now populateUsers returns the promise instead of undefined.
As concluded in comments: you get an error because populateUsersreturns a promise and accepts a done callback argument, while one of these is expected, not both.
Related
To make my code cleaner I want to use fetched API data in a few different functions, instead of one big. Even though I 've did manage to reffer to that data in other functions, the problem is the API im a fetching throws different, randomized results every time it is called. And so the output from userData() does not equal that from userData2(), even though my intention is different and I'd like the result variable contents to be the same between functions.
const getData = () =>
fetch("https://opentdb.com/api.php?amount=10").then((response) =>
response.json()
);
const useData = async () => {
const result = await getData();
console.log(result);
};
const useData2 = async () => {
const result = await getData();
console.log(result);
};
Your getData() function returns a promise. One fun fact about promises is that while they can only resolve once, that resolved value can be accessed and used as many times as you want.
const dataPromise = getData();
const useData = async () => {
const result = await dataPromise;
console.log(result);
};
const useData2 = async () => {
const result = await dataPromise;
console.log(result);
};
Using await resolves the promise value, the equivalent of...
dataPromise.then((result) => {
console.log(result);
});
// or `dataPromise.then(console.log)` if you like brevity
I like to point this out about the fetch-api... you should always check the Response.ok property
const getData = async () => {
const res = await fetch("https://opentdb.com/api.php?amount=10");
if (!res.ok) {
throw new Error(`${res.status}: ${await res.text()}`);
}
return res.json();
};
If I have these lines:
const service = await getService('player');
const players = await service.players();
Can I use this one-liner version instead? Are they equivalent?
const players = await (await getService('player')).players();
Is there an even more streamlined way to write it?
Short answer: It's equivalent to in terms of result.
However, As #CertainPerformance's comment, you should use the first snippet to be able to debugger (as well as to follow best practice) like this.
let getService = (str) => new Promise(resolve => setTimeout(() => resolve({players: getPlayers}), 1000));
let getPlayers = () => new Promise(resolve => setTimeout(() => resolve("Response data"), 1000));
async function run() {
const service = await getService('player');
console.log(service); // debugger to watch response of each async func
const players = await service.players();
console.log(players); // debugger to watch response of each async func
}
run();
I have a Firebase Function which sends back data from databases. The problem is sometimes I have to return data all of 3 collections, sometimes only need from 1 and sometimes 2 of them. But this is an antipattern. How can I improve my code?
Right now I'm creating a function, which returns a promise, in which I'm using await for getting db values and this is wrapped in try{} block.
module.exports.getList = (uid, listType) => new Promise(async (resolve, reject) => {
let returnValue = [];
try {
if (listType.contains("a")) {
const block = await db.collection('alist').doc(uid).get();
returnValue.push(block);
}
if (listType.contains("b")) {
const like = await db.collection('blist').doc(uid).get();
returnValue.push(like);
}
if (listType.contains("c")) {
const match = await db.collection('clist').doc(uid).get();
returnValue.push(match);
}
} catch (e) {
return reject(e);
}
return resolve(returnValue);});
How should I modify this snippet in order to not be an antipattern? Or is it not because of the try-catch block?
You can make the getList function async instead, without new Promise or try/catch:
module.exports.getList = async (uid, listType) => {
const returnValue = [];
if (listType.contains("a")) {
const block = await db.collection('alist').doc(uid).get();
returnValue.push(block);
}
if (listType.contains("b")) {
const like = await db.collection('blist').doc(uid).get();
returnValue.push(like);
}
if (listType.contains("c")) {
const match = await db.collection('clist').doc(uid).get();
returnValue.push(match);
}
return returnValue;
};
Calling it will return a Promise that rejects with an error if there's an asynchronous error, or it will resolve to the desired array.
Note that unless there's a good reason to await each call in serial, you can use Promise.all instead, so that the requests go out in parallel, and make the code a lot more concise in the process:
module.exports.getList = (uid, listType) => Promise.all(
['alist', 'blist', 'clist']
.filter(name => listType.contains(name[0]))
.map(name => db.collection(name).doc(uid).get())
);
I'm a novice with Javascript and am struggling to understand how or at least, how best to return array values to another script to assert agains their values.
The context is I want to use Puppeteer to obtain some string values from WebElement attributes and then use the Chai expect library to assert for correct values( or otherwise).
The code I have thus far is:
//app.spec.js
const clothingChoice = await frame.$eval('#option-clothing-5787', e => e.getAttribute('value'));
const groceryChoice = await frame.$eval('#option-clothing-4556', e => e.getAttribute('value'));
const wineChoice = await frame.$eval('#option-clothing-4433', e => e.getAttribute('value'));
const voucherChoice = await frame.$eval('#option-clothing-3454', e => e.getAttribute('value'));
function testFunction() {
return new Promise(function(resolve, reject) {
resolve([clothingChoice, groceryChoice, wineChoice, voucherChoice]);
});
}
async function getChosenItemValues() {
const [clothingChoice, groceryChoice, wineChoice, voucherChoice] = await testFunction();
console.log(clothingChoice, groceryChoice, wineChoice, voucherChoice);
}
getChosenItemValues();
module.exports = getChosenItemValues;
};
I simply need to understand how to import the values that are currently simply printed out as:
1|clothing|option 1|grocery|option 1|wine|option 1|voucher|option
...into another file test.js in which I want to use chai to assert for their presence like so:
expect(clothingChoice).to.equal('1|clothing|option');
Try this:
// app.spec.js (.spec is normally reserved for test files, you may to change the name to avoid confusion)
const clothingChoice = frame.$eval('#option-clothing-5787', e => e.getAttribute('value'));
const groceryChoice = frame.$eval('#option-clothing-4556', e => e.getAttribute('value'));
const wineChoice = frame.$eval('#option-clothing-4433', e => e.getAttribute('value'));
const voucherChoice = frame.$eval('#option-clothing-3454', e => e.getAttribute('value'));
async function getChosenItemValues() {
return await Promise.all([clothingChoice, groceryChoice, wineChoice, voucherChoice]);
}
module.exports = {
getChosenItemValues
};
NOTE: does frame.$eval definitely return a Promise? I've not had any experience with Puppeteer.
// test file
const app = require('/path/to/app.spec.js');
describe('Suite', function() {
it('Returns expected values', function(done) {
app.getChosenItemValues()
.then(res => {
const [clothingChoice, groceryChoice, wineChoice, voucherChoice] = res;
// assertions here
done();
});
});
});
Excuse me if the test functions aren't in the correct format, I don't use Mocha or Chai.
I have a bunch of async functions, that I always or nearly always want to call synchronously. So we all know the pattern
async function somethingcool() {
return new Promise(resolve => {
setTimeout(resolve, 1000, "Cool Thing");
});
}
const coolthing = await somethingcool();
console.log(coolthing);
But I have this cool module called manycooolthings which offers many cool things, all via async functions that I always or nearly always want to await on.
import * as cool from 'manycoolthings';
await cool.updateCoolThings();
const coolThing = await cool.aCoolThing();
const anohtherCoolThing = await cool.anotherCoolThing();
const rus = await cool.coolThingsAreUs();
await cool.sendCoolThings();
await cool.postCoolThing(myCoolThing);
await cool.moreCoolThings();
const thingsThatAreCool = await cool.getThingsThatAreCool();
Extremely contrived and silly example, to illustrate the point. I do have a genuine use case, a set of tests based on puppeteer where most functions are async and they almost always want to be awaited on.
There must be a better way to avoid all the await pollution of our JavaScript code.
It would be great if could do something like
import * as cool from 'manycoolthings';
await {
cool.updateCoolThings();
const coolThing = cool.aCoolThing();
const anotherCoolThing = cool.anotherCoolThing();
const rus = cool.coolThingsAreUs();
cool.sendCoolThings();
cool.postCoolThing(myCoolThing);
cool.moreCoolThings();
const thingsThatAreCool = cool.getThingsThatAreCool();
}
Or even just
import * as cool from 'manycoolthings';
cool.updateCoolThings();
const coolThing = cool.aCoolThing();
const anotherCoolThing = cool.anotherCoolThing();
const rus = cool.coolThingsAreUs();
cool.sendCoolThings();
cool.postCoolThing(myCoolThing);
cool.moreCoolThings();
const thingsThatAreCool = cool.getThingsThatAreCool();
without having to worry if the method being called is async or not, because it's defined as an auto await function or something.
If you're unhappy with multiple awaits or thens, you can make a little "sequence" helper:
let _seq = async fns => fns.reduce((p, f) => p.then(f), Promise.resolve(null))
and use it like this:
result = await seq(
_ => cool.updateCoolThings(),
_ => _.aCoolThing(),
_ => _.anotherCoolThing(),
_ => _.coolThingsAreUs(),
)
which is almost your snippet #2.