mscdex/node-ftp - 等待承诺解决太早

时间:2021-07-03 14:10:38

标签: javascript node.js asynchronous ftp

我对异步函数太陌生了,如果我弄错了,很抱歉。目前,我已尝试使用 mscdex node-ftp 节点包通过 FTP 上传给定目录中的所有文件夹。虽然这很完美,但承诺在我的函数中解析得太早,并且会在上传完全完成之前在主函数中运行其他代码。

有没有办法让uploadFolder函数只有在uploadFolder函数完全完成后才运行代码?


var c = new Client(config);

let uploadFolder = (folderToUpload) => {
  try {
    return new Promise((resolve, reject) => {
      let folderName = folderToUpload.substring(
        folderToUpload.lastIndexOf("/") + 1
      );

      let replacedItem = folderToUpload.replace(folderName, "");

      let uploadOrder = Glob.sync(folderToUpload + "/**/*");

      c.on("ready", () => {
        let uploadOrderFiltered = uploadOrder.map((element) => {
          return element.replace(replacedItem, "");
        });

        c.mkdir(`/${folderName}`, false, (error) => {
          if (error) {
            console.log(`Error, MKDIR Error ${error}`);
            c.end();
          }
        });

        for (let i = 0; i < uploadOrderFiltered.length; i++) {
          if (uploadOrderFiltered[i].includes(".")) {
            c.put(
              `${replacedItem}${uploadOrderFiltered[i]}`,
              `/${uploadOrderFiltered[i]}`,
              (error) => {
                if (error) {
                  console.log(`Error, UPLOADING Error ${error}`);
                  c.end();
                }
              }
            );
          } else {
            c.mkdir(`/${uploadOrderFiltered[i]}`, false, (error) => {
              if (error) {
                console.log(`Error, MKDIR Error ${error}`);
                c.end();
              }
            });
          }
        }

        c.end();
      });

      c.connect(config);
      resolve();
    });
  } catch (error) {
    console.log(`[FTP ERROR]: ${error}`);
    reject();
  }
};
const { createFolder } = require("./createFolder");

let asyncFunc = async () => {

// ... CODE BEFORE (Runs Fine)

//PROMISE BROKEN
  await uploadFolder(
    "D:/GitHub/Procedural-Artwork-Generation/nexRender/Project/Output/zeroTwoTemplate_AJDKAJKDJKADJKA"
  );
  console.log("[FTP]: Upload Done");

//Upload Done is running before uploadFolder function is completed.

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

解决方案正如jfriend00所说,我太早解决了我的承诺。我最终做的是用 c.on("ready") 块之外的单独事件处理程序替换 resolve() 方法,该处理程序侦听“end”事件。

更新后的代码如下


var c = new Client(config);

let uploadFolder = (folderToUpload) => {
  try {
    return new Promise((resolve, reject) => {
      let folderName = folderToUpload.substring(
        folderToUpload.lastIndexOf("/") + 1
      );

      let replacedItem = folderToUpload.replace(folderName, "");

      let uploadOrder = Glob.sync(folderToUpload + "/**/*");

      c.on("ready", () => {
        let uploadOrderFiltered = uploadOrder.map((element) => {
          return element.replace(replacedItem, "");
        });

        c.mkdir(`/${folderName}`, false, (error) => {
          if (error) {
            console.log(`Error, MKDIR Error ${error}`);
            c.end();
          }
        });

        for (let i = 0; i < uploadOrderFiltered.length; i++) {
          if (uploadOrderFiltered[i].includes(".")) {
            c.put(
              `${replacedItem}${uploadOrderFiltered[i]}`,
              `/${uploadOrderFiltered[i]}`,
              (error) => {
                if (error) {
                  console.log(`Error, UPLOADING Error ${error}`);
                  c.end();
                }
              }
            );
          } else {
            c.mkdir(`/${uploadOrderFiltered[i]}`, false, (error) => {
              if (error) {
                console.log(`Error, MKDIR Error ${error}`);
                c.end();
              }
            });
          }
        }

        c.end();
      });

      c.on("end", () => {
        resolve();
      });

      c.connect(config);
    });
  } catch (error) {
    console.log(`[FTP ERROR]: ${error}`);
    reject();
  }
};

答案 1 :(得分:0)

我并没有完全遵循你想要完成的所有事情,但我认为如果你使用 promise-ftp 库来封装 node-ftp 库,那么这段代码会简单得多,然后你就可以使用 async/await 对所有异步操作进行流量控制。

这是它看起来如何的一般想法(我试图复制你的逻辑,但没有真正理解你在做什么,也没有能力测试它——所以把它当作方向,而不是直接跑出来的东西框):

const Client = require('promise-ftp');
const glob = require('glob-promise');

async function uploadFolder(folderToUpload) {
    let folderName = folderToUpload.substring(folderToUpload.lastIndexOf("/") + 1);
    let replacedItem = folderToUpload.replace(folderName, "");
    let uploadOrder = await glob(folderToUpload + "/**/*");
    const c = new Client(config);
    try {
        await c.connect();
        await c.mkdir(`/${folderName}`, false);
        let uploadOrderFiltered = uploadOrder.map((element) => {
            return element.replace(replacedItem, "");
        });
        for (let f of uploadOrderFiltered) {
            if (f.includes(".")) {
                await c.put(`${replacedItem}${f}`, `/${f}`);
            } else {
                await c.mkdir(`/${f}`, false);
            }
        }
    } catch (e) {
        console.log('FTP error: ', e);
        throw e;
    } finally {
        c.end();
    }
}

关于您的逻辑的一些观察:

  1. 您似乎假设存在“。”在文件名中表示它是一个文件,而不是一个目录。当然不能保证,因为目录可以有“。”在他们之中。最好从您的原始文件系统中获取该信息,也许从您的 Glob 调用中获取。
  2. 您正在使用 Glob 的同步版本。 glob-promise 将 promise 封装在 glob 接口周围,因此您也可以将 async/await 与它一起使用,然后使用异步版本。
  3. 您的原始代码会提前创建一个客户端对象并将其存储在模块级别,然后重用它。如果同时进行多个对 uploadFolder() 的调用,则会产生问题。因此,我为每个对 uploadFolder() 的单独调用创建了一个新客户端。
  4. 这个新版本通过返回的 promise 将错误返回给调用者,这样调用者就可以知道它何时完成以及是否有错误。您的代码没有将大部分错误反馈给调用者。