用Nodejs遍历云存储文件

起因

最近想要将云存储中的文件去重。因为有现成的Nodejs的API,所以打算用Nodejs实现此功能。
伪代码如下:

scanDir = function(uri){
    return new Promise(function(resove, reject) {})
}
getFileInfo = function(uri){
    return new Promise(function(resove, reject) {})
}

dealDir = aysnc function(uri) {
    await scanDir(uri).then(function(res){
        for (v of res) {
            if (res.type === "Folder") {
                dealDir(uri + '/' + v);
            } else {
                getFileInfo(uri + '/' + v).then(function(res){
                    //将文件信息存入数据库
                })
            }
        }
    }).catch(function(){})
}

递归什么的,用起来得心应手,在加上Promise这种大杀器,配合await用起来更是无人能挡。几百个文件的测试没问题,但真正运行起来之后,爆栈了。

分析

按道理讲,我只有3层目录,就算递归也不会有多少函数入栈。那么到底是什么原因呢?
因为Promise的递归容易出问题,比如上面的例子,虽然dealDir里面的scanDir函数被await了,但是dealDir函数本身还是压在栈里,并没有阻塞运行。
这样一层层地dealDir压入栈,迟迟等不到scanDir函数回调的响应导致了最终的爆栈。
如图:

解决方法

最后我选择了一种相对安全的方式:避免递归,用队列处理。
伪代码如下:

scanDir = function(uri){
    return new Promise(function(resove, reject) {})
}
getFileInfo = function(uri){
    return new Promise(function(resove, reject) {})
}

dealDir = aysnc function(uri) {
    let folders = []
    folders.push(uri)
    while (folders.lenth > 0) {
        let tmpfolder = folders.shift();
        await scanDir(tmpfolder).then(function(res){
            for (v of res) {
                if (res.type === "Folder") {
                    folders.push(tmpfolder + '/' + v);
                } else {
                    getFileInfo(tmpfolder + '/' + v).then(function(res){
                        //将文件信息存入数据库
                    })
                }
            }
        }).catch(function(){})
    }
}

参考资料

了解JavaScript的工作原理可以参考:
美团面试题:https://segmentfault.com/a/1190000015057278
JavaScript是如何工作的:
https://github.com/xitu/gold-miner/blob/master/TODO/how-javascript-works-event-loop-and-the-rise-of-async-programming-5-ways-to-better-coding-with.md

猜你喜欢

转载自www.cnblogs.com/bugutian/p/11244369.html