Q Promises 没有按预期解决
Q Promises not resolving as expected
我正在构建一个使用 glob 和 q 的脚本。我希望能够向它发送一个字符串 "src/**/*.js"
,并让它在每个路径名上调用一个函数。我想扩展它,这样我就可以向它传递一个像 ["stage1/**/*.js", "stage2/**/*.js"]
甚至 [["stage1/**/*.js", "stage2/**/*.js"], "stage3/**/*.js"]
这样的 glob 数组,本质上让我可以任意定义顺序依赖性,而不用真正关心组本身的顺序。
我想出了以下脚本:
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接口。这是使用上述模块的 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");
}
}
据我所知,在文档方面这应该可行。但是,如果我使用 returns 一堆文件的 glob,"finished" 文本将在所有文件打印出来之前打印出来。
我以为是Q.all()
的使用,以及某种整理检查失败。但实际上 Q.all()
似乎在工作,从来没有遗漏任何文件。奇怪的是,据我所知,与 promises.reduce()
中的 then
操作链接似乎并没有等到其他承诺完成。甚至似乎完全忽略了 then
链的顺序...
我以为 console.log
可能是异步操作,但根据其他帖子,在我的情况下,console.log
应该是同步操作...这里有人能看出我对此有什么误解吗,或者发现我遗漏的错误?
问题是您的迭代器函数的 if else 子句可能 return 两个分开的承诺:
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(主要是如何获得已解决的承诺)所以我相信你可以改进它:
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;
};
我正在构建一个使用 glob 和 q 的脚本。我希望能够向它发送一个字符串 "src/**/*.js"
,并让它在每个路径名上调用一个函数。我想扩展它,这样我就可以向它传递一个像 ["stage1/**/*.js", "stage2/**/*.js"]
甚至 [["stage1/**/*.js", "stage2/**/*.js"], "stage3/**/*.js"]
这样的 glob 数组,本质上让我可以任意定义顺序依赖性,而不用真正关心组本身的顺序。
我想出了以下脚本:
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接口。这是使用上述模块的 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");
}
}
据我所知,在文档方面这应该可行。但是,如果我使用 returns 一堆文件的 glob,"finished" 文本将在所有文件打印出来之前打印出来。
我以为是Q.all()
的使用,以及某种整理检查失败。但实际上 Q.all()
似乎在工作,从来没有遗漏任何文件。奇怪的是,据我所知,与 promises.reduce()
中的 then
操作链接似乎并没有等到其他承诺完成。甚至似乎完全忽略了 then
链的顺序...
我以为 console.log
可能是异步操作,但根据其他帖子,在我的情况下,console.log
应该是同步操作...这里有人能看出我对此有什么误解吗,或者发现我遗漏的错误?
问题是您的迭代器函数的 if else 子句可能 return 两个分开的承诺:
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(主要是如何获得已解决的承诺)所以我相信你可以改进它:
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;
};