在 Q Promises 中跳过 then 函数的正确方法
Posted
技术标签:
【中文标题】在 Q Promises 中跳过 then 函数的正确方法【英文标题】:Proper way to skip a then function in Q Promises 【发布时间】:2014-03-01 20:40:04 【问题描述】:在我的代码中,根据特定条件,我想跳到done
函数,而不考虑所有then
函数。
这个问题的原始版本在编辑中。以下是我正在处理的实际问题。很抱歉给您带来不便
实际问题:
我正在读取一个文件并处理它。如果文件的内容符合某些条件,我必须对文件系统进行一系列操作(比如读写几个文件),然后执行done
函数。如果条件不成立,我要跳过所有的一系列操作,直接执行done
函数。
我在所有then
函数中返回一个对象(比如说result
),在接下来的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);
);
【问题讨论】:
虽然不确定,但你不能返回一个包含布尔值的对象吗,根据这个布尔值,你的下一个函数将执行是/否。return randomNumber : ..., process : true ;
,在您的下一个电话中:.then(function (data) if(!data.process) return; return data.randomNumber + 1; )
@DieterGoetelen 这将使下一个处理功能非常依赖于上一步。
你能用一个更真实的问题吗(也许你的实际任务,有很多伪代码会发生什么)?您的同步示例并没有多大意义。
【参考方案1】:
这在一定程度上取决于要跳过的条件是什么,您正在执行什么样的操作,以及当条件失败时整个事情有多“有用”。您也许可以在此处使用智能拒绝来传达信息。否则,我相信处理这个问题的正确方法实际上是一组嵌套的 promise 调用。
这也匹配core idea behind promises,它是将同步控制结构带回异步代码执行。一般来说,在使用 Promise 时,您应该首先考虑如何使用同步代码完成任务。如果你考虑一下你的情况,它可能会这样工作:
var contents = readFromFile();
var results = initialOperation(contents);
if (fancyCondition(results))
results = doSomething(results);
results = doMore(results);
processAndPrint(results);
所以你会有一个真正的同步代码分支。因此,在使用 Promise 的异步代码中避免这种情况是没有意义的。如果你可以跳过 的东西,你基本上是在使用 goto 跳转。但相反,您分叉并单独做一些其他事情。
所以回到 Promise 和异步代码,拥有一个带有另一组链式操作的实际分支是完全没问题的,并且符合 Promise 背后的意图。所以上面的代码可能是这样的:
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 的函数时,Promise 管道会自动看起来更干净,而不是从 then
内联创建它们。
【讨论】:
【参考方案2】:然后我们嵌套了 thenable 函数。这是我们首先要使用 Promise 来避免的。
不,这确实是正确的方法。对于分支,您总是需要额外的嵌套级别。如果缩进太大,你仍然可以使用调用子过程的老技巧(这也用于取消嵌套回调函数)。
其他解决方案相当难看。跳过链中的几个then
-handlers,没有更深的嵌套,可以通过抛出异常并拒绝promise来完成;这最终可能会被抓住。它可能适用于一些场景,但我认为这不是一个好主意。
我能想到的另一种方法是将条件结果包装在另一个数据结构中,它可以通过then
s 的链传递。这就像 Haskell 中的 Maybe
或 Scala 中的 Option
一样,您可以在处理程序中使用 map
覆盖它们。但是,这也需要额外的嵌套级别,在链中显式传播任何内容的效率会降低,并且在链中返回的 Promise 会出现问题。
【讨论】:
【参考方案3】:如果我正确理解“跳过”,那么通用解决方案是不在“跳过”条件下返回值,从而允许输入值透明地通过。
例如:
...then(function (randomInteger)
var remainder = randomInteger % 2;
console.log(['Even','Odd'][remainder] + ' number: ', randomInteger);
if(remainder)
return randomInteger + 1;
)...
【讨论】:
但这仍然会执行下一个then
函数,对吧?唯一的区别是,参数是"0": undefined
。
是的,您需要在每个.then()
成功处理程序中应用一些“跳过”逻辑。这就是.then()
链的本质。
不,不是undefined
,正如我所说,如果没有返回,则传递输入值。
当然,您始终可以在随后的.then()
s 中使用带有空错误处理程序的失败路由,但最终的处理程序(在您的示例中为奇数)需要是一个失败处理程序(即.fail(fn)
或.then(null, fn)
)。【参考方案4】:
我使用上下文变量并在承诺链中调用的函数中实现条件逻辑。每个函数都返回相同的上下文变量。这使承诺链保持整洁。使用暗示条件测试的函数名称可以提高可读性。
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);
);
【讨论】:
以上是关于在 Q Promises 中跳过 then 函数的正确方法的主要内容,如果未能解决你的问题,请参考以下文章
我正在尝试实现一个函数,该函数接受数组输入并给出数组的乘积,在 Javascript 中跳过 0 但我只能使用 .reduce