应用程序级别的继续传递风格
不是在表达式/功能块级别进行比较,而是在应用程序级别考虑延续传递样式可以通过其“延续”函数(也称为回调函数)提供流控制优势的途径。让我们以Express.js为例:
每个express 中间件都采用非常相似的 CPS 函数签名:
const middleware = (req, res, next) => {
/* middleware's logic */
next();
}
const customErrorHandler = (error, req, res, next) => {
/* custom error handling logic*/
};
next
是 express 的原生回调函数。
更正: next() 函数不是 Node.js 或 Express API 的一部分,而是传递给中间件函数的第三个参数。next() 函数可以任意命名,但按照惯例,它总是命名为“next”</p>
req
并且res
分别是 HTTP 请求和 HTTP 响应的命名约定。
Express.JS 中的路由处理程序将由一个或多个中间件函数组成。Express.js 会将它们中的每一个传递 给下一个中间件所做更改 的req
,对象,以及一个相同的回调。res
next
app.get('/get', middlware1, middlware2, /*...*/ , middlewareN, customErrorHandler)
next
回调函数用于:
作为中间件的延续:
- 调用
next()
将执行流程传递给下一个中间件函数。在这种情况下,它履行了作为continuation的角色。
也作为路由拦截器:
- 调用
next('Custom error message')
绕过所有后续中间件,并将执行控制传递customErrorHandler
给错误处理。这使得在路线中间“取消”成为可能!
- 调用
next('route')
绕过后续的中间件并将控制权传递给下一个匹配的路由,例如。/获取/部分。
在 JS 中模仿管道
pipe有一个 TC39 提案,但在它被接受之前,我们必须手动模仿 pipe 的行为。嵌套 CPS 函数可能会导致回调地狱,所以这是我尝试更简洁的代码:
假设我们想通过替换起始字符串的部分来计算一个句子“狐狸跳过月球”props
(例如)
const props = " The [ANIMAL] [ACTION] over the [OBJECT] "
替换字符串不同部分的每个函数都使用数组排序
const insertFox = s => s.replace(/\[ANIMAL\]/g, 'fox')
const insertJump = s => s.replace(/\[ACTION\]/g, 'jumps')
const insertMoon = s => s.replace(/\[OBJECT\]/g, 'moon')
const trim = s => s.trim()
const modifiers = [insertFox, insertJump, insertMoon, trim]
我们可以使用reduce
.
const pipeJS = (chain, callBack) => seed =>
callBack(chain.reduce((acc, next) => next(acc), seed))
const callback = o => console.log(o)
pipeJS(modifiers, callback)(props) //-> 'The fox jumps over the moon'
这是pipeJS
;的异步版本
const pipeJSAsync = chain => async seed =>
await chain.reduce((acc, next) => next(acc), seed)
const callbackAsync = o => console.log(o)
pipeJSAsync(modifiers)(props).then(callbackAsync) //-> 'The fox jumps over the moon'
希望这可以帮助!