deno icon indicating copy to clipboard operation
deno copied to clipboard

Failure to release resource with `FsFile.close()` in the `Symbol.AsyncIterator`

Open fwqaaq opened this issue 1 year ago • 4 comments

Version: Deno x.x.x

deno 1.42.4 (release, aarch64-apple-darwin)
v8 12.3.219.9
typescript 5.4.3

I released resource with fd.close() once AsyncIterator has completed the iteration. However, there are some following issues:

done FsFile {}
error: Uncaught (in promise) BadResource: Bad resource ID
                            fd.close();
                               ^
    at FsFile.close (ext:deno_fs/30_fs.js:743:10)
    at Object.next (file:///Users/feiwu/Project/deno/grammY/index.ts:18:32)
    at eventLoopTick (ext:core/01_core.js:168:7)
    at async stream (file:///Users/feiwu/Project/deno/grammY/index.ts:29:33)

But, it still exists and has not been released when I print fd(FsFile).

The source code is as follow:

async function main() {
    const fd = await Deno.open("README.md");
    const reader = fd.readable.getReader();

    const asyncIterator = {
        [Symbol.asyncIterator]() {
            return {
                async next() {
                    while (true) {
                        const { value, done } = await reader.read();
                        if (done) {
                            console.log("done", fd);
                            fd.close()
                        }
                        return { value, done };
                    }
                },
            };
        },
    } as AsyncIterable<Uint8Array>;

    const iterator = asyncIterator[Symbol.asyncIterator]();
    while (true) {
        const { value, done } = await iterator.next();
        if (done) break;
        console.log(value);
    }
}

fwqaaq avatar Apr 21 '24 04:04 fwqaaq

Deno has already closed the file when the reader returns { done: true }, so when you call fd.close() it throws an error as you're trying to close the file again.

It should also be noted fd.readable is already async iterable, so you can just use it directly:

const iterator = fd.readable[Symbol.asyncIterator]();

Jamesernator avatar Apr 21 '24 12:04 Jamesernator

Deno has already closed the file when the reader returns { done: true }, so when you call fd.close() it throws an error as you're trying to close the file again.

If according to what you said, fd should have been released when the function ended, but the fact is that it can still be accessed.

Delete if (done) ..., then add console.log(fd) in the function ended.

fwqaaq avatar Apr 21 '24 13:04 fwqaaq

If according to what you said, fd should have been released when the function ended, but the fact is that it can still be accessed.

This is just how JS works, as long as a variable is in scope you can access it. There is no concept of destructors in JS, instead you simply let the garbage collector remove the object when it is no longer referenced.

This does not mean the file isn't closed, it is, it's just the wrapper object will throw errors if you try to call any of the methods (including .close).

Jamesernator avatar Apr 21 '24 14:04 Jamesernator

This does not mean the file isn't closed, it is, it's just the wrapper object will throw errors if you try to call any of the methods (including .close).

Thank you, bro, I get it. But why is there no documention to explain all of this?

fwqaaq avatar Apr 21 '24 16:04 fwqaaq

This is how all other APIs work - feel free to open a PR to improve the docs here :)

lucacasonato avatar Jun 08 '24 17:06 lucacasonato

@lucacasonato Thank you, I'm trying to improve it.

fwqaaq avatar Jun 09 '24 08:06 fwqaaq