如何知道所有的回调都执行完了?可以做下一步操作了
发布于 9 年前 作者 dbliu91 5656 次浏览 最后一次编辑是 8 年前 来自 问答

今天用nodejs写了个脚本,主要功能是:

遍历一个文件夹,把在该文件夹下(包括子文件夹)的,长或者宽大于1024像素的图片。以json格式存储这份列表到一个文件中。

这个功能之前用python写了一遍。

现在想练手,所以就用nodejs写了一遍。

期间困扰我最久的问题是:文件的遍历是异步的(不确定是不是异步的回调),获取图片的宽高也是异步的(这个确定是异步的),如何知道所有的回调都执行完了?可以做下一步操作了。刚开始百度到的是用async库,可我太笨了看不懂。

最后算是黑客了一下

process.on('beforeExit', function(code) {
    var json = JSON.stringify(file_list,null,2);
    fs.writeFileSync(out_dir + "/file_list.json", json_list );
})

在进程结束前的事件中做写文件的事。也是实在没有想到好的办法。

完整代码如下:

var fs = require('fs');
var sharp = require('sharp');//图片处理库

var root_dir = "../res/ui";
var out_dir = "../res/ui";

var file_set = new Array();

var walk = function(file_name){
    var states = fs.statSync(file_name); 
    if(states.isDirectory()){
        var files = fs.readdirSync(file_name);
        files.forEach(function(file){
            walk(file_name + '/' + file)
        });
    }else if(states.isFile()){
        
        if(file_name.endsWith(".jpg") || file_name.endsWith(".png")){
            sharp(file_name).
            metadata().
            then(function(metadata){
                if(metadata.format=="jpeg" || metadata.format=="png"){
                    if(metadata.width>=1024 || metadata.height>=1024){
                        file_name = file_name.replace(root_dir+"/","") 
                        //console.log(file_name)
                        file_set.push(file_name)
                    }
                }
            })
        }
        
        
    }
}

//遍历'../res/ui'目录
walk('../res/ui')

process.on('beforeExit', function(code) {
    var json_list = JSON.stringify(file_set,null,2);
    fs.writeFileSync(out_dir + "/file_list2.json", json_list );
})



6 回复

哨兵变量


var fs = require('fs');
var sharp = require('sharp');//图片处理库
var Promise = require('bluebird');

var root_dir = "../res/ui";
var out_dir = "../res/ui";

var file_set = new Array();

var key = 0

var after_doThing = function(){
    console.log("after_doThing")
    var json_list = JSON.stringify(file_set,null,2);
    fs.writeFileSync(out_dir + "/file_list2.json", json_list );
}

var doThing = function(file_name){
    if(file_name.endsWith(".jpg") || file_name.endsWith(".png")){
        key++;
        sharp(file_name).
        metadata(
            function(err,metadata){
                
                key--;
                
                if(metadata.format=="jpeg" || metadata.format=="png"){
                    if(metadata.width>=1024 || metadata.height>=1024){
                        file_name = file_name.replace(root_dir+"/","") 
                        //console.log(file_name)
                        file_set.push(file_name)  
                    }
                }
                
                if(key==0){
                    after_doThing()
                }
            }
        )
    }  
}

var walk = function(file_name,cb){
    var states = fs.statSync(file_name); 
    if(states.isDirectory()){
        var files = fs.readdirSync(file_name);
        files.forEach(function(file){
            walk(file_name + '/' + file,cb)
        });
    }else if(states.isFile()){
        cb(file_name)
    }
}

//遍历'../res/ui'目录
walk('../res/ui',doThing)

我谷歌了一下哨兵变量:大致意思是不是就是下面的代码。 var key = 0 key++; key--;

if(key==0){
     after_doThing()
}

@William17 promise要怎么用啊?感觉好吃力啊-_-!

@dbliu91 哨兵变量有可能会不准确. 假如有深层目录, 在你的代码还在walk深层目录的时候, 其它文件可能已经处理完, 这时key为0, 事实上还没处理完. (不过你使用的都是sync方法, 可能不会出现这种问题) 使用Promise的思路其实也比较简单. 在部分地方使用sync方法简化了代码结构

var fs = require('fs');
/**
 * @return {object} Promise
 */
function doThing(fileName) {
   // ...
   // console.log(fileName);
   // do something and return a promise
}

/**
 * @return {object} Promise
 */
function walk(fileName, cb) {
  var pList = [];
  var states = fs.statSync(fileName);
  if (states.isDirectory()) {
    var files = fs.readdirSync(fileName);
    files.forEach(function(file) {
      pList.push(walk(fileName + '/' + file, cb));
    });
  } else if (states.isFile()) {
    pList.push(cb(fileName));
  }
  return Promise.all(pList);
}

walk('filename', doThing).then(function() {
  console.log('done');
}).catch(function(err) {
  console.log(err);
});
回到顶部