不等待嵌套的承诺。

huangapple go评论93阅读模式
英文:

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

  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?"

如果您有任何其他问题,可以随时提出。

英文:

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

forEachasync 操作总是错误的,因为 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
}

huangapple
  • 本文由 发表于 2020年1月3日 13:18:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/59573529.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定