首页 > 解决方案 > 让 fs.readme 与 async await 和 promisify 一起工作

问题描述

我正在尝试创建一个节点脚本,该脚本查看我最近创建的降价笔记的收件箱,在该笔记的顶部找到元数据,在该元数据中找到类别,然后将文件移动到其相关文件夹中。我不断收到错误消息:

(node:82025) UnhandledPromiseRejectionWarning: ReferenceError: paths is not defined

我相信这是因为我的代码没有等待 readFile 函数完成,尽管我已将其标记为 async/await 并将其包装在文件顶部的 promisify 中。有人可以指出我哪里出错了吗?下面的完整代码(其他依赖项用于另一个脚本):

    const fs = require('fs');
    const path = require('path');
    const firstline = require('firstline');
    const moment = require('moment');
    const { promisify } = require('util');
    
    const readFile = promisify(fs.readFile);
    
    const pathToResources =
      '/Users/Rob/Library/Mobile Documents/9CR7T2DMDG~com~ngocluu~onewriter/Documents/Test/Resources/';
    
    function markdownNotesOnly(files) {
      return (notes = files.filter((file) => path.extname(file) === '.md'));
    }
    
    async function getNewPath(note) {
      let oldPath = path.join(__dirname, note);
      let paths = {};
      let newPath = '';
    
      readFile(oldPath, (err, data) => {
        if (err) throw err;
    
        let metadata = data
          .toString()
          .match(/-{3}\n.*\n-{3}/gms)
          .toString();
        let category = metadata.match(/#§-\d{3}-.*/);
    
        if (!category) {
          paths = { oldPath, newPath };
          return paths;
        }
    
        category = category.toString().substring(3);
        newPath = path.join(pathToResources, category);
        paths = { oldPath, newPath };
        return paths;
      });
    }
    
    function sortFiles(startPath) {
      fs.readdir(startPath, (err, files) => {
        if (err) throw err;
    
        markdownNotesOnly(files); // returns array called notes
    
        notes.map(async (note) => {
          await getNewPath(note);
    
          let { oldPath, newPath } = paths;
    
          fs.rename(oldPath, path.join(newPath, note), (err) => {
            if (err) throw err;
            console.log('File moved successfully');
          });
        });
      });
    }

更新:遵循 Mestre San 的建议,今天早上开始工作。如果对任何人有用,这是我完成的代码。

import { readdir, rename } from 'fs';
import { promises as fsPromises } from 'fs';
import { resolve, extname, join } from 'path';
const __dirname = resolve();

const pathToResources =
  '/Users/Rob/Library/Mobile Documents/9CR7T2DMDG~com~ngocluu~onewriter/Documents/Test/Resources/';

function markdownNotesOnly(files) {
  let notes = files.filter((file) => extname(file) === '.md');
  return notes;
}

async function getPaths(note) {
  const metadataRegex = /-{3}\n.*\n-{3}/gms;
  const categoryRegex = /#§-\d{3}-.*/;
  let oldPath = join(__dirname, note);
  let newPath = '';

  const file = await fsPromises.readFile(oldPath);
  if (file instanceof Error) throw err;

  if (!file.toString().match(metadataRegex)) {
    let paths = { oldPath, newPath };
    return paths;
  }

  let metadata = file.toString().match(metadataRegex).toString();
  let category = metadata.match(categoryRegex);

  if (!category) {
    let paths = { oldPath, newPath };
    return paths;
  }

  category = category.toString().substring(3);
  newPath = join(pathToResources, category);
  let paths = { oldPath, newPath };
  return paths;
}

export function sortFiles(startPath) {
  readdir(startPath, (err, files) => {
    if (err) throw err;

    let notes = markdownNotesOnly(files);
    notes.map(async (note) => {
      let paths = await getPaths(note);
      let { oldPath, newPath } = paths;
      rename(oldPath, join(newPath, note), (err) => {
        if (err) throw err;
        console.log('File moved successfully');
      });
    });
  });
}

标签: javascriptnode.jsasynchronous

解决方案


您发布的片段绝对不完整,因为我们只能根据我们在这里看到的内容提供建议,这符合我的考虑:

  1. 您正在创建一个 promisified 函数,但您将它与回调一起使用。你应该选择一种风格。代码现在的方式是您的回调将永远不会被调用。您必须在fs.readFile那里使用或readFile(oldPath).then(data =>. fs.promises.readFile如果它在您正在使用的 Node.js 版本上可用,那就更好了

  2. 我可以知道路径变量确实没有在sortFiles函数内部在线定义。代码在函数内部声明该变量,getNewPath使其在函数内部不可用sortFiles

  3. 该变量notes也未定义。代码notes在函数内部创建变量markdownNotesOnly。虽然不鼓励使用全局范围在函数之间共享这些值,但如果您选择这样做,您绝对应该在该函数之外使用let notes.

  4. sortFiles没有被调用,但是由于它使用的是异步函数并且您没有将任何回调作为参数传递给它,因此它几乎可以像火一样工作并且忘记有点事情

  5. sortFiles函数的名称中有 sort 这个词,但它的主体中有一个 rename 调用,即使您将来也会感到困惑。

但是,让您的代码停止抛出同样的错误的方法是执行以下操作:

'use strict'
const fs = require('fs')
const path = require('path')
// const firstline = require('firstline')
// const moment = require('moment')
const { promisify } = require('util')

const readFile = promisify(fs.readFile)

const pathToResources =
  '/Users/Rob/Library/Mobile Documents/9CR7T2DMDG~com~ngocluu~onewriter/Documents/Test/Resources/'

let notes, paths
function markdownNotesOnly (files) {
  'use strict'
  return (notes = files.filter((file) => path.extname(file) === '.md'))
}

async function getNewPath (note) {
  const oldPath = path.join(__dirname, note)
  // let paths = {}
  let newPath = ''

  return readFile(oldPath).then(data => {
    const metadata = data
      .toString()
      .match(/-{3}\n.*\n-{3}/gms)
      .toString()
    let category = metadata.match(/#§-\d{3}-.*/)

    if (!category) {
      paths = { oldPath, newPath }
      return paths
    }

    category = category.toString().substring(3)
    newPath = path.join(pathToResources, category)
    paths = { oldPath, newPath }
    return paths
  })
}

function sortFiles (startPath) {
  fs.readdir(startPath, (err, files) => {
    if (err) throw err

    markdownNotesOnly(files) // returns array called notes

    notes.map(async (note) => {
      await getNewPath(note)

      const { oldPath, newPath } = paths

      fs.rename(oldPath, path.join(newPath, note), (err) => {
        if (err) throw err
        console.log('File moved successfully')
      })
    })
  })
}

推荐阅读