こんなものを作る
socket.ioを使っているとデータを「受信している or 止まっている」が目視で分かりにくい。
データが入ってくる度にconsole.log
をしているとデータ数によっては画面が勢いよく流れてしまうのでこういった場合はロード中によく見るようなスピナーがあれば良いと考えた。
今回のサンプルはGatsbyjsをビルドする時に画面に表示される物をイメージしている(同じようなものが出る)
import rl from 'readline'
const spin_char = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
let spin_count = 0;
function spin(message) {
process.stdout.write('\x1B[?25l') //カーソルを消す
rl.clearLine(process.stdout, 0) //行をすべて削除
rl.moveCursor(process.stdout, -9999, 0) //一番左側に戻る
process.stdout.write(`${spin_char[spin_count]} ${message}`) //spin_charの配列で描画
spin_count++ //要素番号計算
spin_count >= spin_char.length ? spin_count = 0 : null //要素番号のリセット
}
//process.stderr.write('\x1B[?25h') //カーソルを戻すコードはこれ
setInterval(() => {
spin("Loading");
}, 200);
インストールするライブラリ無しでコピペして実行すればスピナーが回るのがメリットである。
まず console.log
は改行が強制的に入るので使えない。改行せずに画面に文字を描画するコードはprocess.stdout.write()
である。
process.stdout.write('\x1B[?25l')
このコードがないとカーソルが残る。カーソルが残ると画面がちらつくため非常に見栄えが悪くなる。このあとカーソルを再び表示する場合は process.stderr.write('\x1B[?25h')
を使おう。
またES6以降のコードではあるが(拡張子をmjsにする必要がある)Node.jsのコードとして${文字列}
は**テンプレートリテラル(またはテンプレート文字列)という文法の中のプレースホルダー**と呼ぶ。テンプレートリテラルとはバックティック(` `)で文字列を表現すること。これにより文字列中に幾つも変数を挿入できるので便利だ。
clearLine
だけで行の文字が消えるのでは?と思ったが行は削除されるがカーソルの位置が前の文字列の最後で止まったままなので、ずれた位置からスピナーが開始されてしまう。その対応として moveCursor
で先頭に戻している。
moveCursor
の第2引数は9999文字左に移動という意味だがあまりスマートには見えない。もっと良いコードがあるかもしれない。
主に参考にしたサイト[英語]: Build Command-Line Spinners in Node.js
カーソルを消すコードはこちらを参考にした[英語]: https://github.com/visionmedia/node-progress/issues/88
このコードだけだと永遠に回り続けるので、別途ロード等に合わせるコードを用意する必要がある。
さらに拡張してバーでのローディング表示なども試してみたい。