在Q Promises中跳过then函数的正确方法

时间:2014-02-05 12:08:40

标签: javascript node.js promise q

在我的代码中,基于特定条件,我想跳到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);
});

4 个答案:

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