0

我正在尝试在 Node.js 中编写类似“robocopy /mir”的函数,但我似乎无法理解如何按顺序正确执行多个异步函数。

一些背景:

  • 该脚本在 Windows 上运行,因此,我需要找到一些方法来复制文件,同时保留修改时间并接收进度通知。
  • 为了解决这个问题,我继续在 .NET 中编写了我的复制函数(使用 Edge.js 调用它)——这个复制函数只是回调一个节点函数来报告文件复制进度。这件作品完美无缺。

要按顺序复制文件,我的第一个想法是执行以下操作:

Object.keys(filesToCopy).forEach(function(key) {
    var deferred = q.defer();
    var payload = {
        sourcePath: key,
        destPath: filesToCopy[key],
        progressCallback: progressCallback
    };

    console.log('Copying %s...', sourcePath);
    // Edge.js called here
    copyFile(payload, deferred.makeNodeResolver());

    deferred.promise.then(function(result) {
        console.log('%s complete.', result);
    }, function(err) {
        console.error('Error: ', err.message);
    });

    promises.push(deferred.promise);
});

不幸的是,这(如预期的那样)在调用 .NET 函数后立即开始复制每个文件,因此,我会立即收到所有文件的进度通知,并提供如下输出:

1%
2%
1%
2%
3%
3%

似乎我需要一种方法来排队要完成的工作,然后再一次将其全部启动,每个项目在下一个继续之前完成。当所有项目都完成后,我需要得到通知。解决方案似乎很简单,但由于我尝试的每个角度都伴随着另一个问题,所以我仍然无法理解。任何帮助将不胜感激,谢谢!

编辑: 正如我在评论中所述,Bergi 提供的答案是使用一个函数,该函数实际上返回了一个承诺,而我的 Edge.js 函数没有。我能够首先通过使用数组而不是对象来解决我的问题filesToCopy,然后执行以下操作:

  return filesToCopy.reduce(function(prev, curr) {
    return prev.then(function() {
      var deferred = q.defer();
      copyFile(curr, function(err, result) {
        deferred.resolve(result);
        console.log('Completed %s', result);
      });
      return deferred.promise;
    })
  }, q());

这可能不是最好的方法,但它适用于我的用途。

4

2 回答 2

3

也许这样的事情会奏效:

var $j = function(val, space) {
  return JSON.stringify(val, null, space || '')
}
var log = function(val) {
  document.body.insertAdjacentHTML('beforeend', '<div><pre>' + val + '</div></pre>')
}



var files = '12345'.split('').map(function(v) {
  return {
    name: 'file_' + v + '.js',
    load: function() {
      var cur = this;
      var pro = new Promise(function(resolve, reject) {

        log('loading : ' + cur.name);
        
        // we simualate the loading stuff
        setTimeout(function() {
          resolve(cur.name);
        }, 1 * 1000);

      }).then( function( val ) {
        
        // once loaded 
        log('loaded : ' + val);
        return val;
      
      });

      return pro;

    }
  };
});


files.reduce(function(t, v) {

  t.promise = t.promise.then(function(){ 
      return v.load();
  });
  
  return t;
}, {
  promise: Promise.resolve(1)
});

于 2015-11-05T16:33:32.227 回答
0

async.eachSeries在数组或async.forEachOfSeries对象上使用。

循环对象

var async = require('async');
var filesObject = {'file/path/1': {}, 'file/path/2': {}};

async.forEachOfSeries(filesObject, copyFileFromObj, allDone);

function copyFileFromObj(value, key, callback) {
  console.log('Copying file ' + key + '...');
  callback(); // when done
}

function allDone(err) {
  if (err) {
    console.error(err.message);
  }
  console.log('All done.');
}                

循环数组

var async = require('async');
var filesArray = ['file/path/1', 'file/path/2'];

async.eachSeries(filesArray, copyFile, allDone);

function copyFile(file, callback) {
  console.log('Copying file ' + file + '...');
  callback(); // when done
}

function allDone(err) {
  if (err) {
    console.error(err.message);
  }
    console.log('All done.');
}

此处的工作示例:https ://tonicdev.com/edinella/sync-loop-of-async-operations

于 2015-11-05T18:27:41.113 回答