如何在这个简单的程序中避免回调地狱?

时间:2018-07-21 14:08:45

标签: javascript node.js callback

Code

这是注释的完整代码。

//program purpose:
//list all directories in a given path.
//choose a file and print wether it's a regular file  or a directory;
fs = require('fs'); //filesystem
const readline = require('readline-sync');// reads input
var dirPath = readline.question("enter directory path.\n>>> ");
//reads directory with dirPath;
fs.readdir(dirPath,(err,files)=>{
  if (err) {
    console.log("Oopps there has been an error. ");
    console.log(err);
  }else {
    //prints files in the directory.
    for (var i = 0; i < files.length; i++) {
      console.log(i+")"+files[i]);
    }
    //choose a file.
    var filePath = readline.question("Choose a file.\n>>> ");
    //checks if the choice is a file or directory
    fs.stat(dirPath+filePath,(err,stats)=>{
      if (err) {
        console.log("Oopps there has been an error. ");
        console.log(err);
      }else {
        if (stats.isDirectory()) {
          console.log("its a directory.");
          //if its a file print its content
        }else {
          fs.readFile(dirPath+filePath,'utf-8',(err,data)=>{
            if (err) {
              console.log("Oopps there has been an error. ");
              console.log(err);
            }

            else {
              console.log(data);
            }
          })
        }
      }
    })
  }

});

我试图掌握javascript的异步特性,我想重构代码: Code2

问题:第二张图片,readir被文件路径输入打断,我该如何解决,我希望代码看起来不错,并能够递归使用这些功能。

2 个答案:

答案 0 :(得分:1)

ES6生成器可以消除回调地狱。 并且还允许您添加 程序流就像循环, 我已将其添加到您的示例中以显示这是多么容易。

我还添加了相应的require()行,并制作了readline.question 到另一个异步函数中,因此它将作为一个完整的 节点上的示例。

const fs = require("fs");
const readline = require("readline").createInterface({
    input: process.stdin,
    output: process.stdout
});
function* myGenerator(dirPath) {
    const callback = yield;
    const [err1, files] = yield fs.readdir(dirPath, callback);
    if (err1) {
        console.log("Oopps there has been an error. ");
        console.log(err1);
        return;
    }
    //prints files in the directory.
    for (var i = 0; i < files.length; i++) {
        console.log(i + ")" + files[i]);
    }
    //choose a file.
    var filePath;
    while (true) {
        [filePath] = yield readline.question("Choose a file.\n>>> ", callback);
        //checks if the choice is a file or directory
        console.log("aaa", dirPath, "bbb", filePath);
        const[err2, stats] = yield fs.stat(dirPath + filePath, callback);
        if (err2) {
            console.log("Oopps there has been an error. Try again.");
            console.log(err2);
        } else if (stats.isDirectory()) {
            console.log("its a directory. Try again");
        } else {
            break; // OK choice
        }
    }
    // it's a file. Print its content
    const [err3, data] = yield fs.readFile(dirPath + filePath, 'utf-8', callback);
    if (err3) {
        console.log("Oopps there has been an error. ");
        console.log(err3);
        return;
    }
    console.log(data);
}

// Create and run the generator
const gen = myGenerator("./"); // Create it
gen.next(); // Start it
gen.next((...args) => gen.next([...args])); // Set its callback function

通过比较,仅靠承诺不能让您使用循环。 异步/等待方法与使用生成器的好处相似 但它要求您将所有异步调用都包装在Promises中。 因此,我发现生成器更容易。

答案 1 :(得分:0)

有几种方法,使用它们可以使其变得简单。

模块化-使每个回调成为独立的函数

承诺-保留异步操作的最终结果。由于它是面向对象的,因此您将获得流畅的界面。因此,通过链接调用方法。

异步/等待-它是#: import CheckBox kivy.uix.checkbox <ColoredBackground@Image>: font_size: '48sp' color: (.9, .5, .4, 1) canvas.before: Color: rgb: (.9, .9, .9) Rectangle: pos: self.x + sp(2), self.y + sp(2) size: self.width - sp(5), self.height - sp(4) <SampBoxLayout>: orientation: "vertical" padding: 10 spacing: 10 # ---------- Button FileChooser ---------- BoxLayout: orientation: "horizontal" height: 30 Button: text: "FileChooser-1" on_press: root.get_image_one() Button: text: "FileChooser-2" on_press: root.get_image_two() # ---------- Display Images---------- BoxLayout: orientation: "horizontal" height: 30 ColoredBackground: source: " " # <----------- should be the image file selected by FileChooser-1 size: self.parent.width, self.parent.height allow_stretch: True keep_ratio: False ColoredBackground: source: " " # <----------- should be the image file selected by FileChooser-2 size: self.parent.width, self.parent.height allow_stretch: True keep_ratio: False 的功能实现。它的工作方式与Promise相同。

这些无效,因为您可以使用名为async的该库