在我的代码中,基于特定条件,我想跳到done
函数,而不考虑所有then
函数。
此问题的原始版本在编辑中。以下是我正在处理的实际问题。很抱歉给您带来不便
实际问题:
我正在阅读文件并进行处理。如果文件的内容符合某些条件,我必须对文件系统进行一系列操作(比如读写几个文件),然后执行done
函数。如果条件失败,我必须跳过所有一系列操作,我必须直接执行done
功能。
我在所有result
函数中返回一个对象(比如说then
),然后在下一个then
我更新result
并返回它。因此,当完成所有then
后,done
将累积result
。最后,done
将处理result
并打印出来。
因此,如果最初未达到条件,done
将只打印result
(这将是空的)。
Q()
.then(readFile)
.then(function (contents) {
var processResult = process the contents;
if (processResult) {
return {};
} else {
// How can I skip to `done` from here
}
})
.then(function (results) {
// do some more processing and update results
return results;
})
... // Few more then functions similar to the one above
...
.fail(function (exception) {
console.error(exception.stack);
})
.done(function (results) {
// do some more processing and update results
console.log(results);
});
答案 0 :(得分:24)
这取决于要跳过的条件是什么,你正在做什么样的操作,以及当条件失败时整个事情是多么“有用”。您可以在此处使用智能拒绝来传达消息。否则,我认为处理这个问题的正确方法实际上是一组嵌套的promise函数。
这也匹配core idea behind promises,它将同步控制结构带回异步代码执行。通常,在使用promises时,您应首先考虑如何使用同步代码执行任务。如果你考虑一下你的情况,它可能会这样:
var contents = readFromFile();
var results = initialOperation(contents);
if (fancyCondition(results)) {
results = doSomething(results);
results = doMore(results);
}
processAndPrint(results);
所以你会在同步代码中有一个真正的分支。因此,使用promises在异步代码中避免使用它是没有意义的。如果你可以跳过的东西,你实际上是使用带有gotos的跳转。但相反,你分开并分开做其他事情。
因此,回到promises和异步代码,拥有另一组链接操作的实际分支是完全正确的,并且实际上是承诺背后的意图。所以上面的代码看起来像这样:
readFromFile(fileName)
.then(initialOperation)
.then(function (results) {
if (fancyCondition(results) {
return doSomething(results)
.then(doMore);
}
return results;
})
.catch(errorHandler)
.then(processResults)
.then(outputResults); // Or `done` in Q
另请注意,当您开始使用自己返回promises的函数时,promise管道会自动看起来更清晰,而不是从then
内联创建它们。
答案 1 :(得分:9)
但是我们正在嵌套那些可靠的函数。这是我们首先想要使用promises避免的。
不,这确实是正确的方法。对于分支,您将始终需要额外的嵌套级别。如果缩进变得太大,您仍然可以应用调用子过程的旧技巧(这也用于取消回调函数)。
其他解决方案非常难看。跳过链中的一些then
- 处理程序,没有更深的嵌套,可以通过抛出异常并拒绝承诺来完成;这可能最终被抓住了。它可能适用于几种情况,但我认为这不是一个好主意。
我能想到的另一种方法是将条件结果包装在另一个数据结构中,该数据结构可以通过then
链传递。这类似于Haskell中的Maybe
或Scala中的Option
,您可以在处理程序中map
覆盖它们。但是,这还需要额外的嵌套级别,通过链显式传播任何内容的效率会降低,并且链中的返回promise将会出现问题。
答案 2 :(得分:1)
如果我理解“跳过”正确,那么通用解决方案不是在“跳过”条件下返回值,因此允许输入值透明地传递。
例如:
...then(function (randomInteger) {
var remainder = randomInteger % 2;
console.log(['Even','Odd'][remainder] + ' number: ', randomInteger);
if(remainder) {
return randomInteger + 1;
}
})...
答案 3 :(得分:0)
我使用上下文变量并在promise链中调用的函数中实现条件逻辑。每个函数返回相同的上下文变量。这使得承诺链保持整洁。使用提示条件测试的函数名称可以提高可读性。
function processFirstPass(context) {
var processResult = process the contents;
if (processResult) {
context.result = processResult;
}
context.specialTag = ! processResult;
return context;
}
processForOnlySpecialTag(context) {
if (context.specialTag) {
context.result = // do some more processing and update results
}
return context;
}
function process() {
var context = { filename: 'input.txt' };
readFromFile(context)
.then(procesFirstPass)
.then(processForOnlySpecialTag)
.fail(function (exception) {
console.error(exception.stack);
})
.done(function (context) {
// do some more processing and update results
console.log(context.result);
});
}