英文:
Not awaiting nested promise
问题
以下是您要翻译的内容:
"It should be noted that I am pretty new to all of this asynchronous stuff.
I am trying to wait until the existence of a file is verified, whereby the script creates the file if need be, before updating the file. However, I cannot seem to figure out how to do it.
I know that I can use fs.writeFileSync
, but I would prefer to make it asynchronous, so to guarantee that it does not block any user activity.
// this is now detectDriveInfo(), the entire function unedited, verbatim
async function detectDriveInfo(){
const exec = require('child_process').exec
let
totalFreespace = 0,
totalSize = 0,
drives = []
exec('wmic logicaldisk get freespace,name,size,volumename', (error, stdout)=>{
stdout
.trim()
.split('\r\r\n')
.map(value => value.trim().split(/\s{2,}/))
.slice(1)
.sort((a,b) => Number(a[0]) - Number(b[0]))
.forEach(async (value, i, a) => {
renderDriveInfo(...value)
totalFreespace += Number(value[0])
totalSize += Number(value2)
drives.push([value1, Number(value2) - Number(value[0])])
if (i === a.length-1) {
renderDriveInfo(totalFreespace,'ALL',totalSize,'')
updateConfigDrives(drives)
await guaranteeData(drives) // this and its nested promises have to happen/complete
updateData(drives) // before this
}
})
})
}
async function guaranteeData(drives){
const fs = require('fs')
if (!fs.existsSync('./data.json')) {
let json = {}
drives = drives.map(([v]) => v)
drives.forEach(v => {
json[v] = []
})
json = JSON.stringify(json, null, 2)
await fs.writeFile('./data.json', json, 'utf8', (error)=>{
if (error) throw error
console.log('The file, data.json, has been created.')
console.log(json)
})
return
}
}
Console Logs
- should come last
- The file, data.json, has been created.
- {
"C:": [],
"G:": [],
"K:": [],
"D:": [],
"E:": [],
"H:": [],
"J:": [],
"I:": [],
"F:": []
}
What am I doing wrong?"
如果您有任何其他问题,可以随时提出。
英文:
It should be noted that I am pretty new to all of this asynchronous stuff.
I am trying to wait until the existence of a file is verified, whereby the script creates the file if need be, before updating the file. However, I cannot seem to figure out how to do it.
I know that I can use fs.writeFileSync
, but I would prefer to make it asynchronous, so to guarantee that it does not block any user activity.
// this is now detectDriveInfo(), the entire function unedited, verbatim
async function detectDriveInfo(){
const exec = require('child_process').exec
let
totalFreespace = 0,
totalSize = 0,
drives = []
exec('wmic logicaldisk get freespace,name,size,volumename', (error, stdout)=>{
stdout
.trim()
.split('\r\r\n')
.map(value => value.trim().split(/\s{2,}/))
.slice(1)
.sort((a,b) => Number(a[0]) - Number(b[0]))
.forEach(async (value, i, a) => {
renderDriveInfo(...value)
totalFreespace += Number(value[0])
totalSize += Number(value[2])
drives.push([value[1], Number(value[2]) - Number(value[0])])
if (i === a.length-1) {
renderDriveInfo(totalFreespace,'ALL',totalSize,'')
updateConfigDrives(drives)
await guaranteeData(drives) // this and its nested promises have to happen/complete
updateData(drives) // before this
}
})
})
}
async function guaranteeData(drives){
const fs = require('fs')
if (!fs.existsSync('./data.json')) {
let json = {}
drives = drives.map(([v]) => v)
drives.forEach(v => {
json[v] = []
})
json = JSON.stringify(json, null, 2)
await fs.writeFile('./data.json', json, 'utf8', (error)=>{
if (error) throw error
console.log('The file, data.json, has been created.')
console.log(json)
})
return
}
}
Console Logs
1. should come last
2. The file, data.json, has been created.
3. {
"C:": [],
"G:": [],
"K:": [],
"D:": [],
"E:": [],
"H:": [],
"J:": [],
"I:": [],
"F:": []
}
What am I doing wrong?
答案1
得分: 2
你正在混合使用回调和Promise。fs.writeFile
的回调版本返回undefined
,不幸的是,JavaScript 会完全愿意等待它(实际上是不等待任何东西)。
请使用不带回调的 fs Promises API 中的 fs.promises.writeFile
:
await fs.promises.writeFile('data.json', json, 'utf8')
console.log('文件 data.json 已创建。')
console.log(json)
你可能还想 指定文件不应被覆盖,以防在存在检查和写入之间创建了该文件:
await fs.promises.writeFile('data.json', json, {
flag: 'wx',
encoding: 'utf8',
})
然后使用非同步版本的 fs.existsSync
:
if (await fs.promises.access('data.json', fs.constants.F_OK)
.catch(err => err.code === 'ENOENT' || Promise.reject(err))) {
或者完全跳过存在检查,如果创建 JSON 不太昂贵,就依赖于 wx
。
forEach
与 async
操作总是错误的,因为 forEach
会丢弃其操作返回的任何内容,而异步函数的返回值很关键。你需要一个常规循环来串行运行,尽管不清楚 drives
是从哪里来的:
for (const value of stdout) {
// ??
}
await guaranteeData(drives)
console.log('应该最后出现')
// updateData(drives)
最后,detectDriveInfo()
正确解析需要一个exec
的Promise版本。目前它返回的Promise也不会等待操作完成。
英文:
You’re mixing callbacks and promises. The callback version of fs.writeFile
returns undefined
, which unfortunately is a value JavaScript will be perfectly happy to await
for you (by not waiting for anything at all).
Use fs.promises.writeFile
from the fs Promises API with no callback:
await fs.promises.writeFile('data.json', json, 'utf8')
console.log('The file, data.json, has been created.')
console.log(json)
You’ll probably also want to specify that the file should never be overwritten, in case it’s created between the existence check and the write:
await fs.promises.writeFile('data.json', json, {
flag: 'wx',
encoding: 'utf8',
})
Then use the non-synchronous equivalent of fs.existsSync
:
if (await fs.promises.access('data.json', fs.constants.F_OK)
.catch(err => err.code === 'ENOENT' || Promise.reject(err))) {
Or just skip the existence check entirely and rely on wx
if creating the JSON isn’t too expensive.
forEach
with an async
action is always wrong, too, because forEach
discards whatever its action returns, and the return value of an async function is critical. You need a regular loop to run serially, although it’s unclear where drives
comes from:
for (const value of stdout) {
// ??
}
await guaranteeData(drives)
console.log('should come last')
// updateData(drives)
Finally, a promise version of exec
is required for detectDriveInfo()
to resolve correctly. Right now the promise it returns doesn’t wait for the operation to complete either.
答案2
得分: 0
在看到您的代码后,我建议改用现代的 for ... of
循环,其中 await
将按预期工作:
for (const value of stdout) {
// 在这里,await 将按您期望的方式工作
}
英文:
After seeing your code , i would suggest using a modern for … of
loop instead, in which await will work as expected :
for (const value of stdout) {
// Inside this await will work as you aspecting
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论