Reputation: 121
Block 1:
const promise = new Promise((resolve) => {
setTimeout(resolve, 100);
});
Block 2:
const promise = (async () => {
await new Promise(resolve => {
setTimeout(resolve, 100);
});
})();
Are the above two blocks equivalent? Any note-worthy differences?
I know it's a highly contrived example and there's not much purpose for Block 2 here. But a situation I have is where I want to create and store a reference to a promise, but the promise executor function needs to use await to get some data. But declaring new Promise(async (resolve) => {});
is considered an anti-pattern. Is block 2 in this situation any better?
UPDATE: Providing a more concrete example of what I'm trying to do:
export async function getData(request) {
// De-dupe fetches for the same request and return existing promise.
if (map.has(JSON.stringify(request))) {
return map.get(JSON.stringify(request));
}
const thePromise = (async () => {
const [foo, bar] = Promise.all(await getFoo(), await getBar());
const theData = await getTheData(foo, bar);
return theData.some.thing ? 'a' : 'b';
})();
map.put(JSON.stringify(request), thePromise);
return thePromise;
}
Upvotes: 5
Views: 3337
Reputation: 949
In the second approach you can use try
and catch
blocks, like so:
const promise = (async () => {
try {
await new Promise(resolve => {
setTimeout(resolve, 100);
});
} catch(err) {
// handle error here
}
})();
Upvotes: 1
Reputation: 664307
Providing a more concrete example of what I'm trying to do
Your usage of the async
immediately executed function expression is totally fine here, there's nothing wrong with it. Sure, you could have written the same with a .then()
chain, but that wouldn't be exactly as comfortable.
Some minor improvements:
export function getData(request) {
// ^ no need for `async` when you return a promise anyway
const requestKey = JSON.stringify(request); // compute only once
if (map.has(requestKey)) {
return map.get(requestKey);
}
const thePromise = (async () => {
const [foo, bar] = await Promise.all([getFoo(), getBar()]);
// ^^^^^ had `await` keywords in the wrong places
const theData = await getTheData(foo, bar);
return theData.some.thing ? 'a' : 'b';
})();
map.set(requestKey, thePromise);
return thePromise;
}
Upvotes: 0
Reputation: 4425
Not sure if this is what you're referring to when you say
but the promise executor function needs to use await to get some data
but it sounds like you're dealing with some asynchronous call inside of a promise that you need to "wait" for, then resolve
with the data that was returned as a result.
So for example,
EDIT: As pointed by @Bergi in the comments below, you probably shouldn't be doing this (wrapping a promise inside of another promise):
// Assuming you're making an API with `axios` to grab some data
const promise = new Promise((resolve, reject) => {
axios.get('www.example.com/api', {...})
.then(result => {
resolve(result)
})
.catch(error => {
reject(error)
})
})
const callback = (data) => {
console.log('data', data)
}
// `callback` will get called when the `axios.get` "finishes" (resolves)
// with some data after it's done fetching, no need to `await` here
promise.then(callback)
Instead, you could do promise chaining, if needed:
// using the same example from above
const handleResponse = (result) => {
// handle response
}
const handleError = (error) => {
// handle error
}
axios.get('www.example.com/api', {...})
.then(handleResponse)
.then(doSomethingElse)
.catch(handleError)
// or, if you need to make multiple asynchronous calls use `Promise.all`
const handleResponses = (response) => {
const [users, books] = response
// do the rest
}
Promise.all([
axios.get('www.example.com/api/users'),
axios.get('www.example.com/api/books')
])
.then(handleAPIResponses)
.then(doSomethingElse)
.catch(handleError)
Similarly, if you're dealing with the "error first" callback pattern
// `fs.readFile` with Node.js
const promise = new Promise((resolve, reject) => {
fs.readFile('...', (err, data) => {
if (err) {
reject(err)
return
}
resolve(data)
})
})
const callback = (data) => {
console.log('data', data)
}
// again, `callback` will get called when reading a file is done
// and you get the result back
promise.then(callback)
If you need to make multiple calls inside of a promise
and then resolve with the final value, you could do something like the following:
async function promise() {
try {
// assuming API.getUserIds() returns a promise
const userIds = await API.getUserIds(...)
const users = await API.getUsers(userIds)
return users
} catch (err) {
// ...
}
}
const callback = (data) => {
console.log('data', data)
}
// again, `callback` will get called when both API requests
// resolve with some values and when the above function returns `users`
promise().then(callback)
Personally, I'd stay away from #2
, and whatever you're trying to accomplish with that pattern (depending on your case) can be easily done choosing one of the examples above.
Upvotes: 0