我正在使用Node.js的询问者库,当使用承诺时,我仍然得到厄运金字塔,我做错了什么?
仅供参考,查询库API基本上是:
inquirer.prompt([
question1,
question2,
question3,
...
questionX
]).then(function(answers){});
中的答案是一个散列,其中的键代表每个问题。这里没什么特别的。
无论如何,使用API,我总是得到getAnswersToPrompts().then(function(answers){})
,它似乎更方便保持嵌套承诺在前一个…像这样:
function run (rootDir) {
return watchHelper().then(function (answers) {
return chooseDirs({
allowDirs: answers.allow,
originalRootDir: rootDir,
onlyOneFile: false
}).then(function (pathsToRun) {
assert(pathsToRun.length > 0, ' You need to select at least one path.');
return getOptions(availableOptionsForPlainNode).then(function (answers) {
const selectedOpts = answers[ 'command-line-options' ];
return localOrGlobal().then(function (answers) {
const sumanExec = answers.localOrGlobal;
console.log(' => ', colors.magenta.bold([ '$', sumanExec, '--watch', pathsToRun, selectedOpts ].join(' ')));
});
});
});
}).catch(rejectionHandler);
}
我可以这样做:
function run(){
return makePromise()
.then(fn1(data1))
.then(fn2(data2))
.then(fn3(data3))
}
其中fn1,fn2,fn3如下:
function fnX(data){
return function(answers){
return promise(data);
}
}
但是这只会让理解AFAICT变得更复杂
请尽可能清楚,我肯定需要前一个承诺的结果,但有时我需要更早于承诺的结果,甚至更早于承诺的结果。
嵌套函数允许我需要的数据在范围内,感谢闭包等。在调用then
:
function run (rootDir) {
var pathsToRun;
return watchHelper()
.then(function (watchHelperAnswers) {
return chooseDirs({
allowDirs: watchHelperAnswers.allow,
originalRootDir: rootDir,
onlyOneFile: false
});
}).then(function (chooseDirsResult) {
assert(chooseDirsResult.length > 0, ' You need to select at least one path.');
pathsToRun = chooseDirsResult;
return getOptions(availableOptionsForPlainNode);
}).then(function (getOptionsAnswers) {
const selectedOpts = getOptionsAnswers[ 'command-line-options' ];
return localOrGlobal();
}).then(function (localOrGlobalAnswers) {
const sumanExec = localOrGlobalAnswers.localOrGlobal;
console.log(' => ', colors.magenta.bold([ '$', sumanExec, '--watch', pathsToRun,
selectedOpts ].join(' ')));
}).catch(rejectionHandler);
}
但有时我需要promise的结果在那之前或者甚至是结果在那之前
在你的例子中唯一的实例是pathsToRun
。我认为嵌套函数两到三个深度来适应这仍然是可读的,但是你的另一个选择是在承诺链之外定义一个变量,我在上面为pathsToRun
展示了这一点。
最后,您的示例在整个承诺链中使用了三个不同的变量,都称为answers
,这可能会增加混乱。一般来说,我认为对承诺回调结果使用相同的名称是可以的,但为了清晰起见,我在这里重新命名了它们。
@Joe Daley的答案近乎完美,但要再添加一件事。我真的不喜欢对函数顶部的变量赋值。我从来不喜欢async.waterfall/async.series……我也不喜欢承诺……下面的模式应该可以避免这种情况。我们在每个promise回调中积累数据,然后在最后一个promise回调中获得所有数据。
//start
function run (rootDir) {
return watchHelper()
.then(watchHelperAnswers => {
return chooseDirs({
allowDirs: watchHelperAnswers.allow,
originalRootDir: rootDir,
onlyOneFile: false
});
})
.then(chooseDirsResult => {
return getOptions(availableOptions).then((options) => {
return { //accumulate answers
options: options,
pathsToRun: chooseDirsResult
}
});
})
.then((obj) => {
return localOrGlobal().then(answers => {
return Object.assign(obj,{ //accumulate answers
localOrGlobal: answers.localOrGlobal
});
});
}).then((obj) => {
const {...allTheAnswers} = obj;
}).catch(rejectionHandler);
}
繁荣!现在您可以避免对顶部的变量进行尴尬的赋值了。如果你不明白这是怎么回事……问我。