質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.00%

JavaScriptでアクセス時にサーバーからcsvファイルを取得し処理を行いたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 823

KeiL

score 7

前提・実現したいこと

RaspberryPi上ののbottleサーバーを使用し、そこにアクセスしたときにJavaScriptでcsvファイルをサーバーから取得し、そのファイル情報を基に処理を行いたい。

発生している問題・エラーメッセージ

csvファイルの取得を行ってみたが、XMLHttpRequestが同期読み込みは推奨されていないらしくエラー警告が出てしまい、代替方法が分からず困っています。
追記:上手く動作しないときがあります。

(index):23 [Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.

該当のソースコード

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>CSV読み込みサンプルページ</title>
</head>

<body>
    <h1>CSV読み込みサンプル</h1>
    <p>読み込んだCSVが開発コンソールに表示されます。</p>
</body>

<script>
function loadCSV(targetFile) {

    // 読み込んだデータを1行ずつ格納する配列
    var allData = [];

    // XMLHttpRequestの用意
    var request = new XMLHttpRequest();
    request.open("get", targetFile, false);
    request.send(null);

    // 読み込んだCSVデータ
    var csvData = request.responseText;

    // CSVの全行を取得
    var lines = csvData.split("\n");

    for (var i = 0; i < lines.length; i++) {
        // 1行ごとの処理

        var wordSet = lines[i].split(",");

        var wordData = {
            name: wordSet[0],
            age: wordSet[1],
        };

        allData.push(wordData);
    }

    console.log(allData);
}

loadCSV("/static/sample.csv");

</script>
</html>
太郎,21
二郎,18
三郎,15
#!/usr/bin/env python
from bottle import run, route, template, request, static_file

@route("/")
def test():
  return template("sample.html")

@route('/static/<file_path:path>')
def static(file_path):
    return static_file(file_path, root='.')

run(host="0.0.0.0", port=8080)

試したこと

ソースコードは以下のサイトを参考にしました。
https://joyplot.com/documents/2017/03/01/xmlhttprequest-javascript-csv/

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

ん〜、この「RaspberryPi上ののbottleサーバ」はインターネット上に広く公開するんですか?
ローカルのLAN内で完結してるなら別にそれで良いんじゃね?と思いますがいかがでしょう。


推奨されていないらしくエラーが出てしまい、代替方法が分からず困っています。

エラーじゃなくて警告じゃないんですか?
では何故警告が出るか解説していきます。

JavaScriptはシングルスレッドです。
そして(非推奨ですが)document.writeでHTML文字列を無理やり記述してパーサーに解析させる機能が備わっている以上、ブラウザの全ての動作が停止します。

つまり、JavaScriptの実行が終了しなければブラウザがフリーズします。
もし試すなら、下記のJavaScriptを実行してみてください。
見事にブラウザのタブが応答しなくなるはずです。

var i = 0;
while (true) {
  i++;
}

まぁ、XMLHttpRequestはAjaxと呼ばれる技術であり、
その実態は裏側でHTTPリクエストをWebサーバに飛ばしてレスポンスを受け取るという一連の流れです。

ローカルのLAN内同士の通信ならともかく、南米にあるようなサーバだと軽く1秒掛かったりします。
日本のサーバでも負荷がかかって応答に時間が掛かってるような状態だと普通に2〜3秒待たされることもあります。
この2〜3秒が致命的なんですね。
ボタンクリックやリンクのクリックなど、全ての動作がキャンセルされてまるでフリーズしたかのような挙動になります。

なのでファイルアクセスやネットワークアクセスのような遅くなりがちな処理は、
JavaScriptの管轄内ではやらないよ!イベントループという概念で処理していくよ!
…という思想でやっています。

イベントループの詳細はぐぐっていただくとして、
大雑把に言えばイベント置き場に「イベント達成条件、発火する関数」をセットで登録しておきます。
JavaScriptの処理自体は全て一瞬で終わらせて、ブラウザ内部のイベントループ機能で「達成したイベントないかな?」と探し、達成済みのイベントがあれば1つずつ関数を取り出して動かすという風に解決していきます。

「イベントの達成条件」というのはaddEventListenerで指定出来る他にも山のように存在し、
例えばnミリ秒待ってから実行するようなものも存在します。

// 1000ミリ秒=1秒なので、1秒後にコンソールに表示される
setTimeout(function () {
  console.log('hello world');
}, 1000);

代替方法が分からず困っています。

もしJavaScript流儀に従うのであれば非同期でやりましょう。
XMLHttpRequestは大昔のIEがなんかよくわからんけど便利かもしれないから入れておこうと実装した機能です。

2002年にGoogleMapというWebアプリがヒットしてAjaxとして爆発的に普及しましたが、
このXMLHttpRequestが非常にクソな実装であり難解、多くのエンジニアを地獄に叩き落としてきました。
2006年にサードパーティのjQueryライブラリが普及し、エンジニアはAjaxを簡単に実装できるようになりました。

また、2013年頃にはHTML5という仕様でFetch APIが定義され、
IE以外の現行のブラウザの多くはFetch APIをサポートしています。
ローカルで使う予定ならChrome等を使うことになると思うのでFetch APIで実装してみると良いでしょう。
Fetch API - MDN

Fetch APIの関数を発火すると、戻り値がPromiseのインスタンスで帰ってきます。
Promise

Promiseは次世代の非同期処理の表現手法なので勉強してみてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/01/21 09:43 編集

    エラーじゃなくて警告でした。
    警告についての詳しい説明ありがとうございます。
    FetchとPromiseについて調べてみます。
    今はローカル環境で動作させています。
    あと、発生している問題の部分に不備があったので一部修正しました。

    キャンセル

  • 2019/01/23 00:20

    教えていただいたfetch APIを調べて使ってみたところ、警告も出ず上手く動きました。
    ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.00%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる