GVKun编程网logo

javascript – 如何使用promises递归地读取目录树(java递归获取目录下文件列表)

17

以上就是给各位分享javascript–如何使用promises递归地读取目录树,其中也会对java递归获取目录下文件列表进行解释,同时本文还将给你拓展JavaScriptPromises初体验、Ja

以上就是给各位分享javascript – 如何使用promises递归地读取目录树,其中也会对java递归获取目录下文件列表进行解释,同时本文还将给你拓展JavaScript Promises 初体验、JavaScript Promises 相当酷、Javascript Promises学习、javascript – ExpressJS / NodeJS / Promises:从promise链中提前返回等相关知识,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

javascript – 如何使用promises递归地读取目录树(java递归获取目录下文件列表)

javascript – 如何使用promises递归地读取目录树(java递归获取目录下文件列表)

我正在尝试编写一个函数来完成与使用带有promise模式的回调模式编写的相同的函数:

@H_301_6@

@H_301_6@

function readdirRecursive(path,handler,callback)  {
  var errs = [],tree = {};
  fs.readdir(path,function(err,dir)  {
    if(err)return callback(err);
    var pending = dir.length;
    if(!pending)return callback(null,tree);
    dir.forEach(function(file)  {
      var newPath = Path.join(path,file);
      fs.stat(newPath,stats)  {
        if(stats.isDirectory())  {
          readdirRecursive(newPath,subtree)  {
            tree[file] = subtree
            handler(tree,newPath,file,"directory",function(err)  {
              if(err)errs.push(err);
              if(!--pending)return callback(errs.length>0?errs:null,tree);
            });
          });
        } else  {
          tree[file] = null; 
          handler(tree,"file",function(err)  {
            if(err)errs.push(err);
            if(!--pending)return callback(errs.length>0?errs:null,tree);
          });
        }
      });
    });
  });
};

这是我目前的尝试:@H_301_6@

@H_301_6@

function readdirRecursive(path)  {
  var tree = {};
  return Q.Promise(function(resolve,reject,notify)  {
    return readdir(path)
    .then(function(dir)  {
      var futures = [];
      var pending = dir.length;
      if(!pending)return resolve(tree);
      dir.forEach(function(file)  {

        var deferred = Q.defer();
        var subPath = Path.join(path,file);
        futures.push(stat(subPath)
        .then(function(stats)  {
          if(stats.isDirectory())  {
            tree[file] = tree;
            var sub = readdirRecursive(subPath)
            sub
            .then(function(subtree)  {
              notify({
                path:subPath,name:file,type:"directory",done:deferred,pending:pending
              });
              //return subtree;
            },notify);
          } else  {
            tree[file] = null;
            notify({
              tree:tree,path:subPath,type:"file",pending:pending
            });
            //return null;
          }
          //console.log("tree",tree);
          deferred.promise()
          .then(function()  {
            console.log("pending promise");
            if(!--pending)resolve(tree);
          },function(err)  {
            reject();
          });
        }));
      });
      return Q.all(futures)
      .then(function(futures)  {
        console.log("hi",futures);
      });
    });
  });
};

此代码将遍历整个树,但它不会返回树,并且会发生通知操作,但延迟的promise不会解析.@H_301_6@

在通知事件之前启动延迟承诺时,根本不会发生任何事情.@H_301_6@

我知道我可以通过将done函数交给progress事件来解决这个问题,而不是试图给出某种类型的承诺,但是我想在这里充分利用promises,例如,这段代码完全正确我想要它做什么:@H_301_6@

@H_301_6@

function readdirRecursive(path)  {
  var tree = {};
  return Q.Promise(function(resolve,file);
        console.log("file",file);
        /*deferred.promise()
        .then(function()  {
          console.log("pending promise");
          if(!--pending)resolve(tree);
        },function(err)  {
          reject();
        });*/
        futures.push(stat(subPath)
        .then(function(stats)  {
          if(stats.isDirectory())  {
            var sub = readdirRecursive(subPath)
            sub
            .then(function(subtree)  {
              tree[file] = subtree
              notify({
                path:subPath,done:function(err)  {
                  console.log("pending promise");
                  if(err)return reject(err);
                  if(!--pending)resolve(tree);
                },done:function(err)  {
                console.log("pending promise");
                if(err)return reject();
                if(!--pending)resolve(tree);
              },tree);
        }));
      });
      return Q.all(futures)
      .then(function(futures)  {
        console.log("hi",futures);
      });
    });
  });
};

这是将执行这些功能的代码:@H_301_6@

@H_301_6@

readdirRecursive("../").then(function(tree)  {
  console.log("TREE!!!",tree);
},function(err)  {
  console.log("ERROR",err);
},function(progress)  {
  console.log("PRGRESS WAS MADE",progress);
  progress.done();
});

解决方法

我的第一个想法是简单地将原始函数包装在一个承诺中.这通常是我在不重新设计底层代码的情况下执行此操作的方式:

@H_301_6@

@H_301_6@

function readdirRecursiveWithPromise (path,handler) {
    return new Promise((resolve,reject) => {
        readdirRecursive(path,(err,tree) => {
            if (err) {
                reject(err);
            }
            else {
                resolve(tree);
            }
        });
    })
}

不幸的是,当我尝试测试这段代码时,我发现了一些与代码相关的潜在问题.@H_301_6@

首先,我不知道你的’处理程序’应该做什么.您尚未提供此说明或描述它应该做什么.这对问题来说是必不可少的,因为它控制最终的回调是否最终被调用,所以我可以推测“处理程序”控制着这个操作,如果你的’回调’没有被调用,那可能是由于逻辑在你的’处理程序’中.@H_301_6@

下一个问题是你的’pending’变量被设置为总共的文件和目录数,但它只是为目录递减.因此,您的’pending’变量永远不会达到0,并且永远不会调用调用回调的条件代码.@H_301_6@

所以我要摆脱’处理程序’和’待定’,我会告诉你我是如何用从头开始的承诺重写它的.@H_301_6@

这是完整的工作代码示例:https://github.com/ashleydavis/read-directory-with-promises.继续阅读以获得解释.@H_301_6@

让我们从一个基于promise的readdir版本开始,它不是递归的:@H_301_6@

@H_301_6@

function readdir (path) { // Promise-based version of readdir.
    return new Promise((resolve,reject) => { // Wrap the underlying operation in a promise.
        fs.readdir(path,files) => {
            if (err) {
                reject(err); // On error,reject the promise.
            }
            else {
                resolve(files); // On success,resolve the promise.
            }
        });    
    });
};

我们还需要一个基于promise的函数,我们可以用它来确定特定路径的类型(文件或目录):@H_301_6@

@H_301_6@

function determineType (parentPath,childpath) { // Promise-based function to determine if the path is a file or directory.
    return new Promise((resolve,reject) => {
        fs.stat(path.join(parentPath,childpath),stats) => {
            if (err) {
                reject(err);
            }
            else {
                resolve({ 
                    path: childpath,type: stats.isDirectory() ? 'directory' : 'file' // Check if it's a directory or a file.
                }); 
            }
        });
    });
};

现在我们可以展开determineType并创建一个函数,获取一个路径数组并确定每个路径的类型.这使用Promise.all并行执行多个异步操作:@H_301_6@

@H_301_6@

function determineTypes (parentPath,paths) { // Async function to determine if child paths are directories or files.

    return Promise.all(
            paths.map(
                childpath => determineType(parentPath,childpath) // Is the path a directory or a file?
            )
        );
};

现在我们可以构建基于promise的recdive版本的readdir:@H_301_6@

@H_301_6@

function readdirTree (rootPath) { // Read an entire directory tree,the promise-based recursive version.
    return readdir(rootPath) // Initial non-recursive directory read.
        .then(childpaths => determineTypes(rootPath,childpaths)) // figure out the type of child paths.
        .then(children => {
            return Promise.all(children // Use Promise.all to figure out all sub-trees in a parallel.
                .filter(child => child.type === 'directory') // Filter so we only directories are remaining.
                .map(child => {
                    return readdirTree(path.join(rootPath,child.path)) // It's a directory,recurse to the next level down.
                        .then(subTree => {
                            return {
                                path: child.path,subTree: subTree,};
                        });
                })
            );
        })
        .then(children => {
            const tree = {}; // Reorganise the list of directories into a tree.
            children.forEach(directory => {
                tree[directory.path] = directory.subTree;
            });
            return tree;
        });
};

这是一个使用示例:@H_301_6@

@H_301_6@

readdirTree("c:\\some-directory")
    .then(tree => {
        console.log("tree:");
        console.log(tree);
    })
    .catch(err => {
        console.error("error:");
        console.error(err);
    });

我在Github上有一个完整的工作示例:https://github.com/ashleydavis/read-directory-with-promises@H_301_6@

希望它能帮助你前进.@H_301_6@

JavaScript Promises 初体验

JavaScript Promises 初体验

Promise 是什么?

Promise 对象用来进行延迟(deferred) 和 异步(asynchronous) 计算。

一个 Promise 处于以下三种状态之一:

  • pending: 初始状态, 非 fulfilled 或 rejected.
  • fulfilled: 成功的操作.
  • rejected: 失败的操作.

Promise 接口表示为一个值的代理,这个值在promise创建时未必已知. 它允许你将 handlers 与一个异步 action 最终的成功或失败状态关联起来. 这使得异步方法可以像同步方法那样返回值: 异步方法返回一个在未来某个时刻拥有一个值的 promise 来替代最终返回值.

pending状态的promise既可带着一个值成为 fulfilled 状态,也可带着一个reason成为 rejected 状态. 任意情况发生时, 通过promise的 then 方法所排列(queued up)的相应handlers 就会被调用. (当绑定相应的 handler 时,如果 promise 已经处于 fulfilled 或 rejected 状态这个 handler 将会被调用, 所以在异步操作的完成和它的 handler 的绑定之间不存在竞争条件.)

因为 Promise.prototype.then 和 Promise.prototype.catch 方法返回 promises, 所以它们可以被链式调用—一种被称为 composition 的操作.

promises.png

Promise 为何出现?

简单的说,Promise 被当成 callback hell 的救命仙丹。

回调函数是JavaScript的一大特色! node.js官方的api基本都是以会回调方式传递函数返回值。习惯同步编程的对这种异步方式多少会产生水土不服,而且层层嵌套,不知不觉就建造起了一座高高的回调金字塔。针对这种普遍问题,Promise应势而生!

Promise 基本用法

创建 Promise

var promise = new Promise(function(resolve, reject) {
  // 做一些异步操作的事情,然后……

  if (/* 一切正常 */) {
    resolve("Stuff worked!");
  }
  else {
    reject(Error("It broke"));
  }
});

Promise 的构造器接受一个函数作为参数,它会传递给这个回调函数两个变量 resolve 和 reject。在回调函数中做一些异步操作,成功之后调用 resolve,否则调用 reject。

调用 reject 的时候传递给它一个 Error 对象只是个惯例并非必须,这和经典 JavaScript 中的 throw 一样。传递 Error 对象的好处是它包含了调用堆栈,在调试的时候会有点用处。

使用 Promise:

promise.then(function(result) {
  console.log(result); // “完美!”
}, function(err) {
  console.log(err); // Error: "出问题了"
});

“then”接受两个参数,成功的时候调用一个,失败的时候调用另一个,两个都是可选的,所以你可以只处理成功的情况或者失败的情况。

Promise 实践

  1. 值的处理

你可以对结果做些修改然后返回一个新值:

var promise = new Promise(function(resolve, reject) {
  resolve(1);
});

promise.then(function(val) {
  console.log(val); // 1
  return val + 2;
}).then(function(val) {
  console.log(val); // 3
});
  1. 队列的异步操作

你也可以把“then”串联起来依次执行异步操作。

当你从“then”的回调函数返回的时候,这里有点小魔法。如果你返回一个值,它就会被传给下一个“then”的回调;而如果你返回一个“类 Promise”的对象,则下一个“then”就会等待这个 Promise 明确结束(成功/失败)才会执行。例如:

你也可以把“then”串联起来依次执行异步操作。

当你从“then”的回调函数返回的时候,这里有点小魔法。如果你返回一个值,它就会被传给下一个“then”的回调;而如果你返回一个“类 Promise”的对象,则下一个“then”就会等待这个 Promise 明确结束(成功/失败)才会执行。例如:

返回一个值

getJSON(''story.json'').then(function(story) {
  return getJSON(story.chapterUrls[0]);
}).then(function(chapter1) {
  console.log("Got chapter 1!", chapter1);
});

你返回一个“类 Promise”的对象

var storyPromise;

function getChapter(i) {
  storyPromise = storyPromise || getJSON(''story.json'');

  return storyPromise.then(function(story) {
    return getJSON(story.chapterUrls[i]);
  })
}

// 用起来非常简单:
getChapter(0).then(function(chapter) {
  console.log(chapter);
  return getChapter(1);
}).then(function(chapter) {
  console.log(chapter);
});
  1. 错误处理

前面已经看到,“then”接受两个参数,一个处理成功,一个处理失败(或者说肯定和否定,按 Promise 术语):

get(''story.json'').then(function(response) {
  console.log("Success!", response);
}, function(error) {
  console.log("Failed!", error);
});

你还可以使用“catch”:

get(''story.json'').then(function(response) {
  console.log("Success!", response);
}).catch(function(error) {
  console.log("Failed!", error);
});

Promise 被否定之后会跳转到之后第一个配置了否定回调的 then(或 catch,一样的)。对于 then(func1, func2) 来说,必会调用 func1 或 func2 之一,但绝不会两个都调用。而 then(func1).catch(func2) 这样,如果 func1 返回否定的话 func2 也会被调用,因为他们是链式调用中独立的两个步骤。看下面这段代码:

asyncThing1().then(function() {
  return asyncThing2();
}).then(function() {
  return asyncThing3();
}).catch(function(err) {
  return asyncRecovery1();
}).then(function() {
  return asyncThing4();
}, function(err) {
  return asyncRecovery2();
}).catch(function(err) {
  console.log("Don''t worry about it");
}).then(function() {
  console.log("All done!");
});

Promise API 参考

静态方法

Promise.resolve(promise);
返回一个 Promise(当且仅当 promise.constructor == Promise)

Promise.resolve(thenable);
从 thenable 对象创建一个新的 Promise。一个 thenable(类 Promise)对象是一个带有“then”方法的对象。

Promise.resolve(obj);
创建一个以 obj 为肯定结果的 Promise。

Promise.reject(obj);
创建一个以 obj 为否定结果的 Promise。为了一致性和调试便利(如堆栈追踪),obj 应该是一个 Error 实例对象。

Promise.all(array);
创建一个 Promise,当且仅当传入数组中的所有 Promise 都肯定之后才肯定,如果遇到数组中的任何一个 Promise 以否定结束,则抛出否定结果。每个数组元素都会首先经过 Promise.resolve,所以数组可以包含类 Promise 对象或者其他对象。肯定结果是一个数组,包含传入数组中每个 Promise 的肯定结果(且保持顺序);否定结果是传入数组中第一个遇到的否定结果。

Promise.race(array);
创建一个 Promise,当数组中的任意对象肯定时将其结果作为肯定结束,或者当数组中任意对象否定时将其结果作为否定结束。

Promise 的现行解决方案

其实已经有一些第三方库实现了 Promise 的功能:

  • Q
  • when
  • WinJS
  • RSVP.js

上面这些库和 JavaScript 原生 Promise 都遵守一个通用的、标准化的规范:Promises/A+,jQuery 有个类似的方法叫 Deferred,但不兼容 Promises/A+ 规范,于是会有点小问题,使用需谨慎。jQuery 还有一个 Promise 类型,它其实是 Deferred 的缩减版,所以也有同样问题。

目前的浏览器已经(部分)实现了 Promise。

Chrome 32、Opera 19 和 Firefox 29 以上的版本已经默认支持 Promise。由于是在 WebKit 内核中所以我们有理由期待下个版本的 Safari 也会支持,并且 IE 也在不断的开发中。

要在这两个浏览器上达到兼容标准 Promise,或者在其他浏览器以及 Node.js 中使用 Promise,可以看看这个 polyfill(gzip 之后 2K)。

相关参考

  • http://www.html5rocks.com/zh/tutorials/es6/promises/
  • http://www.w3ctech.com/topic/721
  • https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
  • http://www.codemud.net/~thinker/GinGin_CGI.py/show_id_doc/488

JavaScript Promises 相当酷

JavaScript Promises 相当酷

【直播预告】程序员逆袭 CEO 分几步?

许多的语言,为了将异步模式处理得更像平常的顺序,都包 含一种有趣的方案库,它们被称之为 promises,deferreds,或者 futures。JavaScript 的 promises ,可以促进关注点分离,以代替紧密耦合的接口。 本文讲的是基于 Promises/A 标准的 JavaScript promises。[http://wiki.commonjs.org/wiki/Promises/A]

Javascript Promises学习

Javascript Promises学习

Promise对象的三个状态

  • pending(进行中)
  • fulfilled(已成功)
  • rejected(已失败)

Promise代表一个异步操作,对象的状态一旦改变,就不会再改变

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject`。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数

// 示例
const promise = new Promise(function(resolve,reject){
	let i = 1==2
	if(i){
		console.log("Promise Success")
		resolve(i)
	}else{
		console.log("Promise Failue")
		reject(i)
	}

}).then(function(value){
console.log("success",value)
},function(error){
	console.log("error",error)
})

 

 

 

相关文档:

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise

https://es6.ruanyifeng.com/#docs/promise

javascript – ExpressJS / NodeJS / Promises:从promise链中提前返回

javascript – ExpressJS / NodeJS / Promises:从promise链中提前返回

当我在服务器上收到发布请求以创建新游戏时,我会执行几个查询.首先,我搜索用户是否已经在游戏中,如果是,则返回游戏.否则,我搜索一个开放的游戏,其中某人正在等待对手并返回该游戏,如果是这样的话.最后,如果没有找到上述状态的游戏,我会创建一个新游戏并返回.所以我的代码看起来像这样:

.post( function(req,res,next){

  ...findUsersExistingGame...

  .then(function(game){
    if(game){ return res.send(game); }
    else{
        return ...findUserWaitingForOpponentsGame...
    }
  }
  .then(function(game){
    if(game){ return res.send(game); }
    else{
        return ...createNewGame...
    }
  })
  .then(function(game){
        return res.send(game);
  })
  .catch(function(err){
       return next(err);
  });

我最终会将每个函数重构为辅助函数以提高可读性,但我需要首先弄清楚链接.我的问题是,如果我在承诺链中找到一个游戏(即用户现有的游戏或其他等待对手的用户),那么我将返回res.send(游戏);但是,第三个.then将抛出一个错误,因为我之前的.then()语句返回undefined.如果我想做一个res.send(游戏),我如何早早退出承诺链?

选项1:我已经看到了抛出错误并明确捕获它的建议,但这种感觉从根本上说是错误的,使用错误来控制流量.

选项2:我可以做类似的事情而不是链接承诺,但这类似于“承诺/回调地狱”:

.post( function(req,next){

  ...findUsersExistingGame...

  .then(function(game){
    if(game){ return res.send(game); }
    else{
        ...findUserWaitingForOpponentsGame...
        .then(function(game){
            if(game){ return res.send(game); }
            else{
                return ...createNewGame...
                .then(function(game){
                    return res.send(game);
                });
            }
        })
    }
  }

还有另一种方式(最好是在ES5中,因为我仍然试图从根本上理解承诺,但ES6的答案也是受欢迎的)?

解决方法

这里的主要问题是,沿途的每个步骤都有三个可能的返回值:

>游戏发现
>游戏尚未找到
>寻找游戏时出错

由于promises只是自然地分离错误而没有错误,只要你想以不同的方式处理这三个单独的返回中的每一个,你就会添加一些自己的分支逻辑.

要使用promise结果干净地进行分支需要额外的嵌套级别,并且通常没有理由避免它,因为它将使您的代码最容易遵循并理解其逻辑.

.post( function(req,next) {
    findUsersExistingGame(...).then(function(game) {
        if (game) return game;
        return findUserWaitingForOpponentsGame(...).then(function(game) {
            if (game) return game;
            // createNewGame() either resolves with a valid game or rejects with an error
            return createNewGame(...);
        });
    }).then(function(game) {
        res.send(game);
    },function(err) {
        // send an error response here
    });
});

请注意这是如何简化每个阶段的返回,并返回下一个嵌套的承诺,使事物链,并集中处理将响应发送到一个地方以减少整体代码.

现在,您可以通过让每个函数接受之前的游戏值并让他们检查是否已经存在有效游戏来隐藏其中一些逻辑,则他们什么也不做:

.post( function(req,next) {
    findUsersExistingGame(args)
        .then(findUserWaitingForOpponentsGame)
        .then(createNewGame)
        .then(function(game) {
            res.send(game);
        },function(err) {
            // send an error response here
        });
});

但是,在findUserWaitingForOpponentsGame()中,你必须接受findUsersExistingGame()解析的确切参数,你必须检查游戏是否有效.

function findUserWaitingForOpponentsGame(args) {
    if (args.game) {
        return Promise.resolve(args);
    } else {
        return doAsyncFindUserWaitingForOpponentsGame(args);
    }
}

每个函数都将使用args对象解析,该对象上有任何公共参数,并且具有每个级别可以检查的.game属性.虽然这为您提供了一个很好的清洁控制流,但它确实在每个函数中创建了额外的代码,它强制每个函数接受作为前一个函数输出的参数(因此您可以直接链接).你可以决定哪个更好.

今天关于javascript – 如何使用promises递归地读取目录树java递归获取目录下文件列表的介绍到此结束,谢谢您的阅读,有关JavaScript Promises 初体验、JavaScript Promises 相当酷、Javascript Promises学习、javascript – ExpressJS / NodeJS / Promises:从promise链中提前返回等更多相关知识的信息可以在本站进行查询。

本文标签: