恰当的方式来跳过Q Promise中的then函数

在我的代码中,基于特定的条件,我想跳过done函数,而不pipe所有的函数。

这个问题的原始版本是在编辑。 以下是我正在处理的实际问题。 抱歉给你带来不便

实际问题:

我在读文件并处理它。 如果文件的内容符合一定的条件,就必须对文件系统进行一系列的操作(比如读写几个文件),然后执行donefunction。 如果条件失败, 我必须跳过所有的一系列操作,我必须直接执行done函数

我在所有的函数中返回一个对象(让我们说result ), then在下一次我更新result并返回它。 那么,当所有这些都完成后,就会有累积的result 。 最后, done会处理result并打印出来。

所以,如果条件最初没有得到满足,那么只会打印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); }); 

这取决于什么条件可以跳过,你正在做什么样的操作,以及当条件失败时整个事情是多么“有用”。 你可能会在这里使用明智的拒绝来传递信息。 否则,我相信处理这个问题的正确方法实际上是一组嵌套的promise调用。

这也符合承诺背后核心思想 ,即将同步控制结构带回asynchronous代码执行。 一般来说,当使用promise时,你应该首先考虑如何使用同步代码来完成任务。 如果你考虑一下你的情况,那可能是这样的:

 var contents = readFromFile(); var results = initialOperation(contents); if (fancyCondition(results)) { results = doSomething(results); results = doMore(results); } processAndPrint(results); 

所以你会在同步代码中有一个真正的分支。 因此,在使用promises的asynchronous代码中避免这种情况是没有意义的。 如果你可以跳过的东西,你基本上使用跳转gotos。 但是,相反,你分开分开做一些其他的事情。

因此,回到承诺和asynchronous代码,有一个实际的分支与另一组链接的操作是完全正常的,实际的背后是承诺背后的意图。 所以上面的代码可能是这样的:

 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 

还要注意,当你开始使用自己返回promise的函数时,promisepipe道会自动查看更清晰,而不是从那里以内联方式创build它们。

但是,我们正在嵌套可行的function。 这是我们首先想要避免使用承诺。

不,这确实是正确的方法。 对于分支 ,您将始终需要额外的嵌套级别。 如果缩进太大,您仍然可以应用调用子程序的旧技巧(也用于解除embeddedcallback函数)。


其他解决scheme是相当丑陋的。 可以通过抛出exception并拒绝承诺来跳过一些链接上的处理程序,而没有更深的嵌套。 这可能会在最后被抓到。 这可能适用于一些场景,但我不认为这是一个好主意。

我能想到的另一种方法是将条件结果包装到另一个数据结构中,这个数据结构可以通过s链来传递。 这就像Haskell中的Maybe或者Scala中的Option ,你可以在处理程序中map它们。 然而,这也需要额外的嵌套层次,在链中没有明确地传播任何东西的效率会降低,并且会在链中返回的承诺上出现问题。

如果我正确理解“跳过”,那么通用解决scheme不是在“跳过”条件下返回一个值,从而允许input值透明地传递。

例如:

 ...then(function (randomInteger) { var remainder = randomInteger % 2; console.log(['Even','Odd'][remainder] + ' number: ', randomInteger); if(remainder) { return randomInteger + 1; } })... 

我使用上下文variables并在promise链中调用的函数中实现条件逻辑。 每个函数都返回相同的上下文variables。 这使诺言链保持整洁。 使用提示条件testing的函数名可以提高可读性。

 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); }); }