簡體   English   中英

使用 promise 對 Node 的事件循環感到困惑

[英]Confused about Node's event loop by using promises

我正在編寫一個遞歸函數,它創建選定文件目錄的對象樹。 我的代碼有效,但順序錯誤。 我看不到我的代碼的輸出。 這是代碼:

const fs = require("fs");

const basePath = process.argv[2];
const result = {};

const isDirectory = path => {
  return new Promise((resolve, reject) => {
    fs.lstat(path, (err, stats) => {
      if (err) reject("No such file or Directory");

      resolve(stats.isDirectory());
    });
  });
};

const createTree = (path, target) => {
  return new Promise((reject, resolve) => {
    fs.readdir(path, (err, list) => {
      for (const item of list) {
        const currentLocation = `${path}/${item}`;
        isDirectory(currentLocation).then(isDir => {
          console.log(result); //I CAN SEE THE RESULT HERE
          if (!isDir) {
            target[item] = true;
          } else {
            target[item] = {};
            resolve(createTree(currentLocation, target[item]));
          }
        });
      }
    });
    reject("Somthing went wrong while getting the list of files");
  });
};

createTree(basePath, result)
  .then(() => console.log("result --->", result)) //BUT NOT HERE
  .catch(err => console.log("Consume Error ==>", err));

我也用async await完成了它,但我很好奇為什么它不適用於承諾。

這是async await的完整工作示例:

const fs = require("fs");

const basePath = process.argv[2]; //Getting the path
const result = {};

//Function to check my path is exist and it's a directory
const isDirectory = async path => {
  try {
    const stats = await fs.promises.lstat(path); //Used istat to get access to the "isDirectory()" method
    return stats.isDirectory();
  } catch (error) {
    throw new Error("No such file or Directory");
  }
};

//Recursive function that should create the object tree of the file system
const createTree = async (path, target) => {
  try {
    const list = await fs.promises.readdir(path);
    for (const item of list) {
      const currentLocation = `${path}/${item}`;
      const isDir = await isDirectory(currentLocation);
      //If it's a file, then assign it to true
      //Otherwise create object of that directory and do the same for it
      if (!isDir) {
        target[item] = true;
      } else {
        target[item] = {};
        await createTree(currentLocation, target[item]);
      }
    }
  } catch (err) {
    console.log("Somthing went wrong while getting the list of files");
  }
};

//Consuming the createTree function
(async () => {
  try {
    await createTree(basePath, result);
    console.log(result);
  } catch (error) {
    console.log(error.message);
  }
})();

我只是好奇是否有可能做同樣的事情,但只能用承諾。

asyncawait只是語法糖,可以更輕松地使用基於 Promise 的程序。 任何依賴於這些關鍵字的程序都可以重寫為不使用它們 -

// main.js

import { readdir } from "fs/promises"
import { join } from "path"

function createTree (init = ".")
{ const one = path => p =>
    p.isDirectory()
      ? many(join(path, p.name)).then(r => ({ [p.name]:  r }))
      : { [p.name]: true }

  const many = path =>
    readdir(path, { withFileTypes: true })
      .then(r => Promise.all(r.map(one(path))))
      .then(r => Object.assign(...r))

  return many(init)
}

createTree(".")
  .then(v => console.log(JSON.stringify(v, null, 2)))
  .catch(console.error)

現在讓我們添加一些示例文件,以便我們可以看到我們的程序正常運行 -

$ yard add immutable    # (any example package)
$ node main.js

輸出 -

{
  "main.js": true,
  "node_modules": {
    ".yarn-integrity": true,
    "immutable": {
      "LICENSE": true,
      "README.md": true,
      "contrib": {
        "cursor": {
          "README.md": true,
          "__tests__": {
            "Cursor.ts.skip": true
          },
          "index.d.ts": true,
          "index.js": true
        }
      },
      "dist": {
        "immutable-nonambient.d.ts": true,
        "immutable.d.ts": true,
        "immutable.es.js": true,
        "immutable.js": true,
        "immutable.js.flow": true,
        "immutable.min.js": true
      },
      "package.json": true
    }
  },
  "package.json": true,
  "yarn.lock": true
}

如果您希望將init路徑包含在樹中,只需稍作修改即可 -

// main.js

import { readdir } from "fs/promises"
import { join, basename } from "path" // !

function createTree (init = ".")
{ const one = path => p =>
    p.isDirectory()
      ? many(join(path, p.name)).then(r => ({ [p.name]: r })) // !
      : { [p.name]: true }

  const many = path =>
    readdir(path, { withFileTypes: true })
      .then(r => Promise.all(r.map(one(path))))
      .then(r => Object.assign(...r)) // !
      .then(r => ({ [basename(path)]: Object.assign(...r) })) // !

  return many(init)
}

現在樹包含我們的初始路徑 -

createTree(".")
  .then(v => console.log(JSON.stringify(v, null, 2)))
  .catch(console.error)
{ ".":      // <- starting path 
  { ... }
}

要了解如何使用異步生成器編寫此程序,請參閱原始問答

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM