应用程序级别的继续传递样式
不是在表达式/功能块级别进行比较,而是在应用程序级别考虑延续传递样式可以通过其“延续”函数(也称为回调函数)提供流控制优势的途径。我们以Express.js 为例:
每个express middleware 都有一个相当相似的 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”
req 和 res 分别是 HTTP 请求和 HTTP 响应的命名约定。
Express.JS 中的路由处理程序将由一个或多个中间件函数组成。 Express.js 会将req、res 对象中的每一个传递给下一个中间件,其中包含前面中间件所做的更改,以及相同的next 回调。
app.get('/get', middlware1, middlware2, /*...*/ , middlewareN, customErrorHandler)
next 回调函数服务:
-
作为中间件的延续:
- 调用
next() 会将执行流程传递给下一个中间件函数。在这种情况下,它起到了延续的作用。
-
也作为路由拦截器:
- 调用
next('Custom error message') 绕过所有后续中间件并将执行控制传递给customErrorHandler 进行错误处理。这使得在路线中间“取消”成为可能!
- 调用
next('route') 绕过后续中间件并将控制权传递给下一个匹配路由,例如。 /get/part.
在JS中模仿管道
pipe 有一个 TC39 提案,但在它被接受之前,我们必须手动模仿管道的行为。嵌套 CPS 函数可能会导致回调地狱,所以这是我尝试更简洁的代码:
假设我们要计算一个句子'The fox jumps over the moon',通过替换起始字符串的一部分(例如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'
希望这会有所帮助!