提问人:coding_chicken 提问时间:10/31/2023 更新时间:10/31/2023 访问量:55
无法理解此异步示例中的执行流
Can't understand the execution flow in this asynchronous sample
问:
我正在学习 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
答:
0赞
leitning
10/31/2023
#1
发出调用的方式会启动两个异步链,从而导致争用条件,因为无法保证写入调用在关闭调用发生之前发生。
当您有
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 运行之前继续。如果要将它们链接在一起,则必须让函数返回一个 Promise 以附加到链中。then()
如果你想继续使用符号,你需要把它们链接在一起,如下所示:then()
await fileHandle.read()
.then((fileData) => json(request) )
.then((jsonData) => fileHandle.write('[2]') )
或者像这样
await filehandle.read()
.then((fileData) => {
// do some stuff
return json(request);
}).then( (jsonData) => fileHandle.write('foobar') )
这样,调用将等待整个链。await
或者,您可以完全丢失符号,而像这样使用 s:then()
await
let fileData = await fileHandle.read()
let jsonData = await json(request)
await fileHandle.write('[2]')
评论
0赞
coding_chicken
10/31/2023
谢谢它有帮助!如果我需要同时处理来自同一链(在其末尾)中 read()、json()、write() (和其他异步函数)的数据,我是否应该将它们的数据压缩到一个对象中(在链之前声明),或者是否有合适的方法来做到这一点?
0赞
leitning
10/31/2023
在这种情况下,你会做.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/......await Promise.all([ fileHandle.read(), json(request), fileHandle.write('foo') ])
评论