added async promises post
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
53ce7f5e2f
commit
aa23b3906c
|
@ -0,0 +1,76 @@
|
|||
---
|
||||
title: "Async Promise Constructors"
|
||||
date: 2023-02-01T09:39:03Z
|
||||
description: Why you shouldn't use async in your new Promise()
|
||||
url: /2023/2/1/async-promise-constructors
|
||||
type: post
|
||||
mp-syndicate-to:
|
||||
- https://brid.gy/publish/mastodon
|
||||
- https://brid.gy/publish/twitter
|
||||
tags:
|
||||
- nodejs
|
||||
- typescript
|
||||
- javascript
|
||||
- softeng
|
||||
-
|
||||
---
|
||||
|
||||
|
||||
I ran into an interesting typescript/js problem yesterday at work.
|
||||
|
||||
The following code snippet was generating an error and a stack trace that was never being propagated up to the caller:
|
||||
|
||||
```typescript
|
||||
return new Promise(async (resolve, reject) =>{
|
||||
|
||||
const data = await this.client.getObject(bucket, path)
|
||||
|
||||
const buf : any[] = []
|
||||
|
||||
data.on('data', (data) => {
|
||||
buf.push(data)
|
||||
})
|
||||
|
||||
data.on('error', (err) => {
|
||||
reject(err)
|
||||
})
|
||||
|
||||
data.on('end', ()=>{
|
||||
resolve(JSON.parse(Buffer.concat(buf).toString()))
|
||||
})
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
The code basically uses [minio](https://min.io/)'s client library to get the contents of an object in an S3 storage bucket and then wraps the stream that it returns in a promise that will eventually parse the content of the S3 object into a JS object or reject if something went wrong.
|
||||
|
||||
Seasoned js folks may have already spotted the problem (or at least guessed it based on the blog post title).
|
||||
|
||||
I'ved used an `async` function inside my Promise constructor. I'm doing this so that I can make my async call to S3 but this has the added side effect of turning my promise constructer itself into a promise (promise-ception?). Promise constructors can't `await` so effectively if the `getObject` async call fails, the error is lost and nothing happens and the outer promise is never resolved or rejected.
|
||||
|
||||
As it turns out, [eslint has a rule for this](https://eslint.org/docs/latest/rules/no-async-promise-executor) which I had turned off.
|
||||
|
||||
### Solution
|
||||
|
||||
I could make the getObject outer function async and then do the `getObject()` call in the outer layer:
|
||||
|
||||
```typescript
|
||||
|
||||
async function someFunction(){
|
||||
|
||||
const data = await this.client.getObject(bucket, path)
|
||||
|
||||
return new Promise((resolve, reject) =>{
|
||||
const buf : any[] = []
|
||||
|
||||
data.on('data', (data) => { buf.push(data) })
|
||||
data.on('error', (err) => { reject(err) })
|
||||
data.on('end', ()=>{
|
||||
resolve(JSON.parse(Buffer.concat(buf).toString()))
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Now if the `getObject` call fails the whole `someFunction()` fails (effectively the promise that is generated by use of the await/async syntactic sugar is rejected).
|
Loading…
Reference in New Issue