javascript - Q Promise 没有按预期解决

标签 javascript node.js q

我正在构建一个使用 glob 和 q 的脚本。我希望能够向它发送一个字符串 "src/**/*.js",并让它在每个路径名上调用一个函数。我想扩展它,这样我就可以向它传递一个像 ["stage1/**/*.js", "stage2/**/*.js"] 这样的 glob 数组,甚至 >[["stage1/**/*.js", "stage2/**/*.js"], "stage3/**/*.js"],本质上是让我任意定义顺序依赖关系,而不真正关心组本身内部的顺序。

我想出了以下脚本:

var Q = require("q");
var glob = require("glob");

function type(value) {
  return Object.prototype.toString.call(value);
}

function iterate(spec, options, callback) {
  if (spec instanceof Array) {
    // convert spec into list of promises
    var promises = spec.map(function(spec) {
      return iterate(spec, options, callback);
    });

    // reduce promises into chain
    return promises.reduce(function(previous, current) {
      return previous.then(current);
    });
  } else if (type(spec) === "[object String]") {
    return Q.nfcall(glob, spec, options)
      .then(function(files) {
        // map files into list of promises
        var promises = files.map(function(file) {
          return Q.Promise(function(resolve, reject) {
            try {
              callback(file, resolve);
            } catch (error) {
              reject(error);
            }
          });
        });

        // wait for all promises to complete
        return Q.all(promises);
      });
  } else {
    throw new Error("The value passed in must be a string, or array of strings.");
  }
};

module.exports = function(spec, options, callback, finished) {
  options = options || {};
  callback = callback || function(file, resolved) {
    resolved();
  };
  finished = finished || function(error) {
    error ? finished(error) : finished(null);
  };

  iterate(spec, options, callback)
    .then(function() {
      finished(null);
    })
    .fail(function(error) {
      finished(error);
    })
    .done();
};

它使用递归来对事物进行排队,然后公开一个看起来正常的nodejs接口(interface)。这是使用上面模块的index.js 文件。

var example = require("./lib/example");

var files = [
  [
    "./node_modules/q/**/*.json",
    "./node_modules/q/**/*.js"
  ],
  "./node_modules/glob/*.json",
  "./node_modules/glob/*.js"
];

example(files, {}, listFile, finished);

function listFile(filename, done) {
  console.log(filename);
  done();
}

function finished(error) {
  if (error) {
    console.log(error);
  } else {
    console.log("finished");
  }
}

据我所知,从文档 Angular 来看,这应该可行。但是,如果我使用返回一堆文件的 glob,则“完成”文本将在所有文件打印之前打印。

我认为这是使用了Q.all(),并且未能检查完成情况。但实际上 Q.all() 似乎正在工作,从来没有丢失过一个文件。奇怪的是,据我所知,在 promises.reduce() 中与 then 操作链接似乎并没有等到其他 promise 完成。甚至似乎完全忽略了 then 链的顺序...

我认为也许 console.log 是异步操作的,但根据其他帖子,在我的情况下,console.log 应该是同步操作...有人可以吗在这里看看我对此有什么误解,或者发现我错过的错误?

最佳答案

问题是迭代器函数的 if else 子句可能返回两个单独的 promise :

function iterate(spec, options, callback) {
  if (spec instanceof Array) {
    return PromiseA;
  } else if (type(spec) === "[object String]") {
    return PromiseB;
  }
};

它们也需要被链接起来:

function iterate(spec, options, callback, previousPromise) {
  if (spec instanceof Array) {
    previousPromise.then(function(){
      return doStuff();
    })
  } else if (type(spec) === "[object String]") {
    previousPromise.then(function(){
      return doStuff();
    })
  }
  return previousPromise;
};

我想出了这个,但我不熟悉 Q (主要是如何获得已解决的 promise ),所以我相信你可以改进它:

function getPromise(){
    var deferred = Q.defer();
    deferred.resolve();
    return deferred.promise;
}

function iterate(spec, options, callback, promiseChain) {
    console.log('spec:', spec);
    promiseChain = promiseChain || getPromise();
    if (spec instanceof Array) {
        promiseChain = promiseChain.then(function() {
            return spec.reduce(function(promiseChain, spec) {
                return promiseChain.then(function() {
                    return iterate(spec, options, callback, promiseChain);
                });
            }, getPromise());
        })
    } else if (type(spec) === "[object String]") {
        promiseChain = promiseChain.then(function() {
            return Q.nfcall(glob, spec, options)
                .then(function(files) {
                    console.log('files:', files);
                    // map files into list of promises
                    var promises = files.map(function(file) {
                        return Q.Promise(function(resolve, reject) {
                            try {
                                callback(file, resolve);
                            } catch (error) {
                                reject(error);
                            }
                        });
                    });

                    // wait for all promises to complete
                    return Q.all(promises);
                });
        });
    } else {
        throw new Error("The value passed in must be a string, or array of strings.");
    }
    return promiseChain;
};

关于javascript - Q Promise 没有按预期解决,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34143389/

相关文章:

javascript - Angular promise : $q reject return html?

javascript - 从javascript SDK调用FQL时出现 "requires valid signature"错误是什么原因?

php - 第一次尝试无法登录

node.js - Grunt cwd 选项问题

javascript - Q.Promise : How to throw exception in callback correctly?

javascript - 要求内部 Q promise

php - 如何在 1 个输入字段中捕获多个值(如 Facebook 消息)?

javascript - 提交时禁用 AddEventListener

javascript - 类型错误 : Cannot read property 'findAll' of undefined (mariaDB, ExpressJs)

javascript - 如何替换html文件中多个标签的内容? [ Node .js]