无法理解这个异步示例中的执行流程

问题描述 投票:0回答:1

我正在学习 javascript 和 nodejs,但仍然在异步执行方面苦苦挣扎

我知道下面的代码远非最佳实践,但我需要理解为什么,根据是否调用 fileHandle.write('[1]') ,当 fileHandle.write( '[2]') 被调用。

我在nodejs文档中找到了这个,我猜它是相关的,但我想了解事情是如何工作的: “在同一个文件上多次使用 filehandle.write() 而不等待承诺得到解决(或拒绝)是不安全的。对于这种情况,请使用 filehandle.createWriteStream()。”

没有错误的代码:

import {createServer} from 'node:http'
import {open} from 'node:fs/promises'
import {write} from 'node:fs'
import {json} from 'node:stream/consumers'


const serveur = createServer(async (request,response) => {
    const path = './tp_CRUD/storage/my_file.json'
    const fileHandle = await open(path, 'w+')
    try {
        await fileHandle.read()
        .then(() => {
            fileHandle.write('[1]') // <= no error as the file is still opened at this point

            json(request) // promise parsing request content to json
            .then(() => {
                fileHandle.write('[2]') // <= no error as file is still open somehow thanks to [1] line
            })
        })
    } catch {
        console.log('error with POST request')
    } finally {
        fileHandle.close()
    }
    response.end()

})
serveur.listen('3000')

有错误的代码:

import {createServer} from 'node:http'
import {open} from 'node:fs/promises'
import {write} from 'node:fs'
import {json} from 'node:stream/consumers'


const serveur = createServer(async (request,response) => {
    const path = './tp_CRUD/storage/my_file.json'
    const fileHandle = await open(path, 'w+')
    try {
        await fileHandle.read()
        .then(() => {
            json(request) // promise parsing request content to json
            .then(() => {
                fileHandle.write('[2]') // <= error as file is closed despite being in the try{} block ??
            })
        })
    } catch {
        console.log('error with POST request')
    } finally {
        fileHandle.close()
    }
    response.end()

})
serveur.listen('3000')

这是调用堆栈,如果它能以某种方式提供帮助的话

node:internal/fs/promises:436
    const err = new Error('file closed');
                ^

Error: file closed
    at fsCall (node:internal/fs/promises:436:17)
    at FileHandle.write (node:internal/fs/promises:207:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  code: 'EBADF',
  syscall: 'write'
}

Node.js v21.1.0
javascript node.js asynchronous async-await http-post
1个回答
0
投票

调用的方式启动了两个异步链,这会导致竞争条件,因为不能保证写调用在关闭调用发生之前发生。

当你有

await fileHandle.read()
        .then(() => {
            // A
            json(request)
            .then(() => {
                // B
                fileHandle.write('[2]') // <= error as file is closed despite being in the try{} block ??
            })

您正在排队一个与 A 无关的新异步任务 B,并且执行可能会在 B 运行之前继续。如果你想将它们链接在一起,你必须让

then()
函数返回一个 Promise 来附加到链中。

如果您想继续使用

then()
符号,您需要将它们链接在一起,如下所示:

await fileHandle.read()
        .then(() => json(request) )
        .then(() => fileHandle.write('[2]') )

这样,

await
调用将等待整个链。

或者,您可以完全丢失

then()
符号,而只使用
await
,如下所示:

await fileHandle.read()
await json(request) 
await fileHandle.write('[2]')
© www.soinside.com 2019 - 2024. All rights reserved.