combine-middlewares
使い方
const combinedFunction = combineMiddlewares(m1, m2, m3.....)
3ヶ月ぐらいCosenseの中で快調に動いているので書いておくshokai.icon できる事
next()で次のmiddlewareを呼び出せる
app.use(m1, m2, m3, (req, res) => {})
が
m1 -> m2 -> m3 -> 終わり
になる
const result = await next()で次の非同期middlewareの完了を待って、自分に処理を戻せる
m1 -> m2 -> m3
<- <-
次のmiddlewareのreturn valueも取れる
const result = next()
もちろんasync-awaitしなくてもいいので、Reduxのreducerみたいなのも作れる 引数の数は何個でもよい
const m1 = (a, b, c, d, e, f, next) => { }
最後の引数がnextであればいい
Scrapboxでの利用
テキスト入力した時の補完
stringを渡すとstringを返す1つの関数
を作る為に複数の小さな関数を合成している
socket.ioの通信
通信データが実際に処理される前に中身をチェックしたり色々やる
複数の小さな関数の連鎖が色々な項目をチェックして、okならnext()していく
などに使っている
input text tranform
入力したテキストを変形する小さな関数を束ねたやつ
code:transform-text/index.js
const plain = inputText => inputText // 末尾は値をそのまま返す
export default combineMiddlewares(selectionComplete, lastBlankLine, bracketComplete,
〜省略〜,
adjustIndent, ...urlMiddlewares, plain)
この関数がキー入力する毎に実行される
code:components/text-input.js
import transformText from '../lib/transform-text/'
class TextInput extends React.Component {
onInput () {
Lines.addChar(transformText(this.textarea.value))
}
}
inputTextを見てnext()する関数をたくさん用意しておく
1. ページ末尾に常に空行を用意するmiddleware
code:transform-text/last-blank-line.js
export default function lastBlankLine (inputText, next) {
if (Cursor.position.isLastLine()) Lines.insertAfterLastLine('')
return next()
}
2. [が入力されたら]を補完するmiddleware
nextせずreturnすると、次のmiddlewareに繋がらない
code:transform-text/bracket-complete.js
export default function bracketComplete (inputText, next) {
if (inputText === 'return '[' // nextしない
next()
}
3. URLが入力されたら[URL]にする
などなど
socket.ioの受信後になんか処理するやつ
code:server.js
ioreq(socket).response('commit', logger, ignoreWhenShuttingDown, (commit, res) => {
/* ここでcommitを処理する */
res('いいぞ')
})
1. 編集データがサーバーに飛んでくる
2. loggerを通る
3. shutdown中はエラーを返すmiddlewareを通ったり、はじかれたりする
4. commitを処理処理する
5. 終わり
code:middleware.js
function ignoreWhenShuttingDown (req, res, next) {
if (GracefulShutdown.shuttingDown) return // nextしない
next()
}
function logger (commit, res, next) {
debug('received', commit)
next()
}
まとめ
上の2つの例は引数の数が違うけど、動く
next()でつなぐ、next()しなければそこで終わり
return next()で次のmiddlewareのreturn valueを前のmiddlewareに戻す
const combinedFunction = combineMiddlewares(m1, m2, m3.....)で作れる
その他の例
next()に引数を渡せる
next(arg)できる
code:js
const double = async (num, next) => {
await delay(10)
return next(num * 2)
}
const minus1 = async (num, next) => {
await delay(10)
return next(num - 1)
}
const plus10 = async (num, next) => {
await delay(10)
return next(num + 10)
}
const result = await combineMiddlewares(double, minus1, plus10)(3) assert.equal(result, 15)
logger→validator→upper(処理本体)とつなげた例
https://gyazo.com/aa2e6b96af32476fc8f85b1c278e6abc
validatorがエラーを出した後や、upperがclientにレスポンスを返した後で、loggerの3行目に処理が戻る
code:js
async function logger (req, res, next) {
console.log('received', req)
const result = await next() // 次のmiddlewareのreturn valueを待つ
console.log('returned', result)
}
function validator (req, res, next) {
try {
if (!(/^a-z+$/.test(req))) { throw new Error('request must be lower case alphabet.')
}
} catch (err) {
res.error(err)
return err // loggerにエラーを返す
}
return next() // upperへ
}
async function upper (req, res) {
const result = req.toUpperCase()
res(result)
return result // validatorを介してloggerにreturnする
}
io.on('connection', function (socket) {
console.log('new client! ' + socket.id)
ioreq(socket).response('toUpper', logger, validator, upper)
})