diadia

興味があることをやってみる。自分のメモを残しておきます。

VSCODEからmysql接続

https://marketplace.visualstudio.com/items?itemName=formulahendry.vscode-mysql

手順

  1. VSCODEmysql拡張機能をインストール
  2. To add MySQL connection: in Explorer of VS Code, click "MYSQL" in the bottom left corner, then click the + button, then type host, user, password, port and certificate file path (optional) in the input box.

mysqlコンテナに接続する設定

host: localhost  
user: MYSQL_USER値(docker-compose.yml)  
password:MYSQL_PASSWORD値(docker-compose.yml)  

port : ローカルからmysqlコンテナに接続するためのポート  

これで接続できる。

SELECTを使ってみたい test.sqlファイルを作り、SQL文を書く。

SELECT * FROM `products_product`;

そして右クリックでSQLを実行する。 これで使えるようになる。

ちなみにpycharmにもDB接続機能があり、そちらではGUIでデータをインサートする事ができるのでpycharmがつかえるならそちらを使うべき。

vscode|エクスプローラービューに表示するファイルを制御したい

参考資料:

.vscode/settings.jsonで設定すれば良い事がわかった。

{
  "files.exclude": {
    "**/.git": true,
    "**/.svn": true,
    "**/.hg": true,
    "**/CVS": true,
    "**/.DS_Store": true
  }
}

git mergetoolの設定で.gitを表示したかった。

sublimetextをうまく使えるようになりたい

参考になったもの:

Sublime Text2の複数カーソルの使い方 - Qiita

以下のものからuuidのみ取り出したい。 どうすればよいのか?
とったものはシングルクォーテーションで囲む。

{
  "took" : 8,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 8,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "uuid" : "e09cd8f2-e678-7ac3-3825-26135ca4cffd",
          "text_id" : 291
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "uuid" : "194dd474-4947-9010-4e80-de80a562cdab",
          "text_id" : 338
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "uuid" : "b892e69e-75f2-8f42-f37c-3964ed5a1bc0",
          "text_id" : 941
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "uuid" : "adbea952-96bb-964c-428d-0f7932459775",
          "text_id" : 922
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 1.0,
        "_source" : {
          "uuid" : "71c532d6-a719-c31c-bcc6-9d4fee4ca5e7",
          "text_id" : 912
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "6",
        "_score" : 1.0,
        "_source" : {
          "uuid" : "0856e4f5-6b91-7b27-d96b-d72bb2edff0f",
          "text_id" : 567
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "7",
        "_score" : 1.0,
        "_source" : {
          "uuid" : "ec6afdae-11ef-8ed3-e266-5a6a3ba04f51",
          "text_id" : 777
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "8",
        "_score" : 1.0,
        "_source" : {
          "uuid" : "0c501f01-b01d-091e-6f5d-f73ac4c3a449",
          "text_id" : 888
        }
      }
    ]
  }
}

こうしたい。

'e09cd8f2-e678-7ac3-3825-26135ca4cffd',
'194dd474-4947-9010-4e80-de80a562cdab',
'b892e69e-75f2-8f42-f37c-3964ed5a1bc0',
'adbea952-96bb-964c-428d-0f7932459775',
'71c532d6-a719-c31c-bcc6-9d4fee4ca5e7',
'0856e4f5-6b91-7b27-d96b-d72bb2edff0f',
'ec6afdae-11ef-8ed3-e266-5a6a3ba04f51',
'0c501f01-b01d-091e-6f5d-f73ac4c3a449'

やりかたをメモしておく

最初にuuidを選択する。選択したら合致するものを全件選択する(ctrl + shift + G)。 選択したら行末まで移動(ctrl + shift + l) .行末から先頭までコピー。

別のところに貼り付け。でシングルクォーテーションをつける。

elasticsearch python コードスニペット

接続して検索

from elasticsearch import Elasticsearch
from elasticsearch_dsl import connections, Search
from elasticsearch_dsl import Q
es = connections.create_connection(hosts=['localhost'], port=9200)
s = Search(using=es, index="animal", doc_type="_doc")
s.query = Q("match_all", **{})
res = s.execute()
for doc in res:
    print(doc)

検索件数を指定する

extra(size=x)で検索数を指定できる
(elasticsearch_dsl/search.pyを見ると色々わかる)

from elasticsearch import Elasticsearch
from elasticsearch_dsl import connections, Search
from elasticsearch_dsl import Q
es = connections.create_connection(hosts=['localhost'], port=9200)
s = Search(using=es, index="animal", doc_type="_doc").extra(size=1)
s.query = Q("match_all", **{})
res = s.execute()
for doc in res:
    print(doc)

elasticsearchクエリメモ

ルクアップデート

ドキュメント:

バッチ処理 | Elasticsearchリファレンス [5.3] | Elastic

Bulk API | Elasticsearch Guide [7.13] | Elastic

クエリサンプル

PUT animal/_doc/_bulk?pretty
{"update":{"_id":1}}
{"doc":{"content":"最初のバルクアップデートの内容4"}}
{"update":{"_id":2}}
{"doc":{"content":"2番目のバルクアップデートの内容4"}}
{"update":{"_id":3}}
{"doc":{"content":"3番目のバルクアップデートの内容4"}}

# 以下のようにdoc_typeをエンドポイントから排除するのが望ましいようだ
PUT animal/_bulk?pretty
{"update":{"_id":1}}
{"doc":{"content":"最初のバルクアップデートの内容4"}}
{"update":{"_id":2}}
{"doc":{"content":"2番目のバルクアップデートの内容4"}}
{"update":{"_id":3}}
{"doc":{"content":"3番目のバルクアップデートの内容4"}}

java - ElasticSearch: Specifying types in bulk requests is deprecated - Stack Overflow

エラーの場合のレスポンス

更新対象のドキュメントIDがないときは、エラーが出る。 エラーは総括のところでerrors:trueとエラーが存在したドキュメントではstatusに200以外が表示されるようだ。 f:id:torajirousan:20210711122216p:plain

pyhonを使ってバルクアップデート

資料: バルクでドキュメント作成する資料:

Python Elasticsearch 基本的な使い方まとめ - Qiita

バルクでアップデートする際の資料:

https://github.com/django-es/django-elasticsearch-dsl/issues/224#issuecomment-551095445 ("_source"ではなく"doc"を使おうっていう内容)

from elasticsearch import Elasticsearch
from elasticsearch.helpers import bulk
from elasticsearch_dsl import Document, Date, Integer, Keyword, Text, connections
from elasticsearch_dsl import Search, Q

es = connections.create_connection(hosts=['localhost'])

data_list = []
data2 = {"_op_type": "update",
         "_id": 2,
         "_index": "animal",
         "doc": {"content": "new22222"}}

data3 = {"_op_type": "update",
         "_id": 3,
         "_index": "animal",
         "doc": {"content": "new3333"}}

data_list.append(data2)
data_list.append(data3)

bulk(es, data_list)

メモ:

  • elasticsearch_dslでbulkを扱えるのか結局分からなかった。
  • bulkの参考資料は普通のelasticsearchモジュールを使っているのが全てだった。
  • バルクで100MB以上のデータを扱うときはエラーが出るらいい。その際は非同期のものを使えば、そのエラーは避けられる。

docker環境でデバッグする方法を調べた

同期と所感

vscodeデバッグできれば様々な言語、フレームワークでも同じようにデバッグ環境を構築できるのではと期待している。 そんなわけで今回はvscodeでdockerのデバッグ環境構築を調査し、やってみた。

デバッグ環境構築して感じのは、コンテナのリモートデバッグと言われるジャンルでも、特別なやり方をせず、ローカルのデバッグ方法の延長線上にあったことだった。(vscode拡張機能を1つ追加し、組み合わせてデバッグを実現していると感じた。) 段階を踏んで試みれば、この類のデバッグは難しい作業ではないと感じた。

採用したデバッグ方法

調べてみて分かったことは、コンテナ環境でデバッグする種類には大きく分けて2種類ある。細かく見れば4種類あることが分かった。 他の言語やフレームワークでも同じようにデバッグしたいと思うので、ソースコードをいじって言語特有のライブラリを仕込んでデバッグする方法は避けた。ライブラリを使わないで実現しようとするとvscode拡張機能を使う方法に絞られた。

1.拡張機能を利用しない方法(ptvsdの利用)

2.拡張機能を利用しない方法(debugpyの利用)

3.拡張機能を利用する方法(Remote Containersをの利用)

4.拡張機能を利用する方法(Remote Developmentの利用)

こんな事書いてあった。

This Remote Development extension pack includes three extensions:

  • Remote - SSH
  • Remote - Containers
  • Remote - WSL

環境構築概要

.devcontainer/devcontainer.jsonを作成し、その後に再度remote-containersでコンテナ内部に入る。コンテナに入ったらローカルでデバッグ環境作るようにlaunch.jsonを作成し、デバッグを実行する。これだけだった。
コンテナ内に入ると拡張機能をインストールする作業があるがdevcontainer.jsonは設定ファイルで、毎回インストールする拡張機能を登録するとインストールしなくても済むようにできる。 最初のコンテナに入ることをRemote Containersは可能にしてくれてる。 Remote Containersはこのコンテナに入ることと,.devcontainerディレクトリ以下を作ってくれるのが役割だと今の所認識している。

手順

1 docker-composeで動くものを作っておく。serviceはdjangoのアプリだけではなくpostgresも合わせたdocker-compose.ymlで問題ない。

2 Remote Container拡張機能をインストールする

3 コマンドパレットを開き、でremote containers extensionを探す。選択肢として Add Development Container Configuration Filesがあるはずなのでそれを選択する。そしてFrom docker-compose.ymlを選択。そうするとdocker-compose.ymlに書かれているserviceの選択を迫られるのでdjangoアプリを選択する。 f:id:torajirousan:20210624175512p:plain

その結果.devcontainer以下が作られる。 f:id:torajirousan:20210624180002p:plain

4 次に緑部分を押すとメニューが表示されるのでRepen in Container を選択し、起動したコンテナ内に入る。 f:id:torajirousan:20210624180108p:plain f:id:torajirousan:20210624180253p:plain

5 コンテナに入ればその後はいつもどおりローカルでデバッグする手順を踏めば良い。(launch.jsonがなければ作成してデバッグ)

注意点

f:id:torajirousan:20210624181730p:plain

コンテナで起動しているサービスにアクセスする場合はターミナルに書かれているようにhttp://127.0.0.1:8000/にアクセスすれば良いというわけではない、ポート番号はランダム?に設定されているのでcommand+クリックでブラウザを開くこと。今回のケースはポートは49114番だった。

amplify aws

ネット上のaws amplify の情報は新旧いろいろ混ざっている。細々した疑問を整理したい。

前提

自分のやりたいことはvue3でamplifyを動かしたい

amplify とvue + viteの組み合わせについて

まずviteで動かすのはかなり困難が伴うことが分かったのでvue cliで実装することが望ましいと分かった。そもそも動かせるとして後にどこに影響してくるか分からないのが怖い。ここはVue CLIが良いと分かった。

https://stackoverflow.com/questions/66912795/in-vite-vue3-ts-project-aws-amplify-failed-to-resolve-components

Vite not working with aws-amplify package · Issue #685 · vitejs/vite · GitHub

Not working with aws-cli / aws-amplify · Issue #1374 · vitejs/vite · GitHub

amplifyとvue + vue cliCSSフレームワーク

現在Vue3はvuetifyに対応しておらず、tailwindを使う場合もある。その時はライブラリの依存関係に注意して環境を作ればなんとかなった印象。公式ドキュメントにはvue cliを使ってtailwindを導入する事例もないし、そこらへんの記事を見て試してもうまく行かないことが多かったが、良い記事を見つければなんとかなった。

EventBusとHub問題(これらは同一のものとして考えてあげる)

まずAmplifyEventBusとHubは同じ役割を果たすものだろうという認識になった。機能的には全く別のものではない事がわかった。

https://stackoverflow.com/questions/61900300/gridsome-aws-amplify-importing-event-bus-breaks-logout-button-component

上によると、amplifyEventBusはレガシーだからHubを使いましょうとある。 確かにamplify 公式ドキュメントのUI Component部分をみれば、legacyとlatestに分かれていて、legacyの部分にeventBusを使う説明が書いてある。このlegacyかlatestの部分で使うライブラリが変わってくるのだけれども、コレもその1つだった。

EventBusとHub問題(イベント時に処理を付け加えたい時に使う)

Hubはどんな時に使えばよいのか。これも1つの問題だった。この問題はこのようにも置き換えられる。amplifyが準備してくれる機能はどこまでカバーしてるいるのか。 カバーをしていないところでHubを使うだろうことはわかるのだが、どこまでカバーしているかは知らず困った。特に最初の方はHubを使わないでもamplifyのUIコンポーネントを使えば認証系はすべて解決すると思っていた。この認識は誤りであった。

使用するライブラリ

amplifyドキュメントUI component部分にはLatestバージョンとLegacyバージョンのドキュメントが存在する。 それぞれで利用するライブラリが変わり、そのためインストールするライブラリを変える必要がある。

Legacyバージョンのインストールするライブラリは以下の通り。

npm i aws-amplify
npm i aws-amplify-vue

Amplify UI (Legacy) - Amplify Docs

Latest版のライブラリのインストールは一通りではなく、Vueのバージョンでインストールするライブラリが変わってくることに注意したい。

Vue2

yarn add aws-amplify @aws-amplify/ui-vue

Vue3

yarn add aws-amplify @aws-amplify/ui-components

割とライブラリの組み合わせをよく見て記事を見ないと全然できるようにならないのでこの点は十分気をつけたい。

実際にVue3の場合で組み立てた際はaws-amplify @aws-amplify/ui-componentsをインストールすればよく。その他必要となるものはなかった。

vue cliでもtailwind.cssをセットアップできたのでメモしておく

環境

macos

node -v
v15.1.0

npm -v
7.0.8

vue --version
@vue/cli 4.5.12

npm list vue
vue@2.6.14

"postcss": "^7.0.35",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.1.4",

※ vue3でも試したところうまく行った(vue@3.1.1)

参考資料

メイン資料
How to Setup Tailwind CSS in Vue 3 | by Victor Onuoha Martins | Apr, 2021 | JavaScript in Plain English

npmでビルドする方法を参考にさせていただきました https://tech.medpeer.co.jp/entry/better-tailwind-css

セットアップ手順

プロジェクト作成

vue create tailwind-app
cd tailwind-app

参考資料のように

Error: PostCSS plugin tailwindcss requires PostCSS 8.

これが後々でてきたので、tailwindに関わるインストールは以下を実行した

npm install -D tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9

tailwind.config.js やpostcss.config.jsのファイルを作成。

npx tailwindcss init -p

このファイルが作成される。

// tailwind.config.js
module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}

ファイルを以下のように変更

// tailwind.config.js
  module.exports = {
    purge: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
    darkMode: false, // or 'media' or 'class'
    theme: {
      extend: {},
    },
    variants: {
      extend: {},
    },
    plugins: [],
  }
mkdir src/styles && touch src/styles/app.css
/* ./src/styles/app.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

tailwindでビルドしたcssファイルをインポートする

// main.js(javascript)
import { createApp } from 'vue';
import App from './App.vue';
import './styles/index.css'; // コレ
createApp(App).mount('#app');

※ src/styles/index.cssを作成するには以下のようにする

// package.json
"scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "build:css": "tailwindcss build src/styles/app.css -o src/styles/index.css" // コレ
  },
// index.cssを作成
npm run build:css

App.vueを以下のようにする

<!-- App.vue -->
<template>
  <div class="justify-center flex bg-yellow-300 items-center h-screen">
    <div class="text-4xl">
      Hello 👋🏼
    </div>
  </div>
</template>
<script>
export default {
  name: 'App',
};
</script>

画面を表示させてみる

npm run serve

f:id:torajirousan:20210609032348p:plain

Amplifyを使ってみた|なぐり書きメモ

AWS Amplifyドキュメント:

https://docs.aws.amazon.com/amplify/index.html

AWS amplify

AWS Amplify enables developers to develop and deploy cloud-powered mobile and web apps. The Amplify Framework is a comprehensive set of SDKs, libraries, tools, and documentation for client app development. The Amplify Console provides a continuous delivery and hosting service for web applications.

AWS Amplifyはクラウドを使ったモバイルアプリやウェブアプリの開発や、デプロイする開発者に手助けする。

ホスティングサービスがあって簡単にデプロイできる。 しかもCI、CD機能があるのでpushするだけで自動で最新のバージョンをデプロイできるようになる。 Amplify Consoleがそれらの機能を担っている。

githubなどリポジトリの連携が必要。 ものによってはroleが必要。

ホスティングだけを試したいならこの記事がわかりやすかった。

【Amplify入門】ReactもVue.jsも使わないシンプルな静的サイトを構築する | DevelopersIO

今の所のイメージ

ユーザーが触るフロントエンド側のアプリケーション(単純なhtmlのみのサイトまたはjavascriptも構成するサイト、vue, reactなどのjavascriptフレームワークを使用したwebアプリケーション、android,ios,flutterなどのモバイルアプリケーション)のデプロイ機能を担う(Amplify console)。

フロントエンドに対し、バックエンドは柔軟に決めることができそう。 amplifyでバックエンド機能を提供する他(amplify CLI)、開発者がバックエンドを作成しフロントと連携できる。 amplifyでバックエンドを作る場合は、amplify CLIを使い、AWSのリソースを作成し、バックエンド機能を作っていく。amplify CLIを使うと、複雑なAWSのマネージド・サービスをコンソールの質問形式に答えるだけで希望するサービスが使える利便性がある。

構成要素

  • Amplify CLI
  • Amplify Framework
  • Amplify Console

Amplify CLI

ドキュメント:https://docs.amplify.aws/cli/auth/overview

The Amplify Command Line Interface (CLI) is a unified toolchain to create AWS cloud services for your app. Let’s go ahead and install the Amplify CLI.

Amplify CLIのインストール

npm install -g @aws-amplify/cli

Get started - Installation - Amplify Docs

amplify statusコマンドについて このコマンドはカレントディレクトリに依存しているらしく、カレントディレクトリがどこであるかでコマンド結果が変わる。 amplifyディレクトリを含むカレントディレクトリで有効に機能することは確認している。

Amplify CLIを使うにはnpmでインストールする。そして amplify add authをやると認証機能を追加することができる。

Configure the Amplify CLI

amplify configure

ローカルにAmplifyCLIをセットアップするにあたり、AWSアカウントとローカルのAmplifyCLIをつなげる調整をする。

To set up the Amplify CLI on your local machine, you have to configure it to connect to your AWS account.

https://docs.amplify.aws/cli/start/install#configure-the-amplify-cli

amplify のバックエンドを削除する場合にはどのようにすればよいか? Amplify CLIでやるのか、Amplify コンソールを使うのか

ソーシャル認証の実装(amplify CLI

https://docs.amplify.aws/lib/auth/social/q/platform/js

フロントエンドの実装(vuejs)

amplify delete

amplify delete

//結果
? Are you sure you want to continue? This CANNOT be undone. (This would delete all the environments 
of the project from the cloud and wipe out all the local files created by Amplify CLI) Yes
⠋ Deleting resources from the cloud. This may take a few minutes...
Deleting env:dev

amplify deleteコマンドはすべての環境とamplify CLIによって作られたローカルファイルの削除をやってくれるようだ。

smplify variables

Environment variables are key-value pairs that are available at build time. These configurations can be anything, including the following: Database connection details Third-party API keys Different customization parameters Secrets

ビルドするときに使うkey-valueのペアのことを環境変数といい、これはamplify consoleで設定する。

環境変数の設定

環境変数はamplify consoleで設定する https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/environment-variables.html#setting-env-vars

環境変数の利用

環境変数の利用はamplify consoleで設定する

https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/environment-variables.html#access-env-vars

ソーシャルサインインの設定方法

googleの認証を通したいときにエラーになてしまったのでいかが必要だとわかった。

https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/environment-variables.html#creating-a-new-backend-environment-with-authentication-parameters

変数はこちらから選ぶ https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/environment-variables.html#amplify-console-environment-variables

amplify authの機能でログイン

ログインが成功するとローカルストレージにいろんな項目が保存される事がわかった。

UserAttributes: [{Name: "sub", Value: "d8b66bc8-6fb8-4107-bbe6-bf856484b59b"}, {Name: "email_verified", Value: "true"},…]
0: {Name: "sub", Value: "d8b66bc8-6fb8-4107-bbe6-bf856484b59b"}
1: {Name: "email_verified", Value: "true"}
2: {Name: "phone_number_verified", Value: "false"}
3: {Name: "phone_number", Value: "+81090********"}
4: {Name: "email", Value: "******@gmail.com"}
Username: "d8b66bc8-6fb8-4107-bbe6-bf856484b59b

Route53メモ

ドキュメント

https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/Welcome.html

Route53の中心機能

使う場合には3つのステップを踏んで利用する事ができる

  1. ドメイン名の登録
  2. インターネット上のトラフィックドメインのリソースに誘導する
  3. リソースの健全性をチェック

DNSの仕組み

ドメイン登録 -> レジストラに登録 -> レジストラを通じてregistryという会社にドメインとipを登録する

Route53の仕様

ユーザーがドメイン登録 ↓ Route53側でpublic hosted zoneを自動で作成してくれる

ユーザーはドメインのみ作成すればよかった(amplifyに関しては)

Promiseを理解するために役に立った資料

Promiseという概念を理解するに当たり以下の記事が大いに役に立った。こちらを読めば理解できる。

levelup.gitconnected.com

levelup.gitconnected.com

以下は自分がPromiseについて整理するために記録しておく。

そもそも自分はaxiosを使っていて、どうやらそれをthenを使うかasync awaitを使えばやり過ごせるって認識でいたのでasync awaitをノリで使いつづけ同期、非同期の話から解説する話がよく分かっていなかった。

そもそもなんでPromise説明を探しているのにコールバックが話題に出てくるのか?

A . 非同期処理はcallbackなしでは語れない概念で非同期処理のPromiseにはcallbackの説明がでてきてしまう。

const callbackFuncA = function () {
    console.log("this is callback a");
};

setTimeout(callbackFuncA, 3000);
console.log("setTimeoutは実行している");

// 結果
setTimeoutは実行している
this is callback a

setTimeoutでcallbackFuncAを呼ぶ文がまさしく非同期なのだ。同期処理ならば、setTimeoutの文を実行すると3秒間コードが止まった後に、callbackFuncAを呼び、実行する。callbackFuncAが終了したら次の行に行ってconsole.log("setTimeoutは実行している");が実行されるはずだ。しかしながら結果は異なる。最初にconsole.log("setTimeoutは実行している");の結果が表示されて、その後callbackFuncAの結果が表示されている。これはsetTimeoutをまず実行して、待ち時間の間に次の行を実行しているからこのような結果になる。

javascriptは処理に時間がかかる場合にはそこで処理を止めることはなく、次のコードを実行する仕様になっているらしい。時間がかかる処理が終わったあとに続く処理をつなげたいときにコールバックは使われる。

JavaScriptのエコシステムは伝統的にはスレッドを使わない計算モデルを使い、それの効率をあげる方向で進化してきました。 例えば、スリープのような、実行を行の途中で止めるような処理は基本的に持っていませんでした。 10秒間待つ、というタスクがあった場合には、10秒後に実行される関数を登録する、といった具合の処理が提供され、その場で「10秒止める」という処理を書く機能は提供されませんでした

非同期処理 — 仕事ですぐに使えるTypeScript ドキュメント

JavaScriptでは時間のかかる処理を実行する場合、完了した後に呼び出す処理を処理系に渡すことはあっても、そこで処理を止めることはありません。 タイマーを設定する setTimeout() 関数の実行自体は即座に完了し、その次の行がすぐ呼ばれます。 そして時間のかかるタイマーの待ちが完了すると、渡してあった関数が実行されます。 処理が終わるのをじっくり待つ(同期)のではなく、完了したら後から連絡してもらう(非同期)のがJavaScriptのスタイルです。 昔のJavaScriptのコードでは、時間のかかる処理を行う関数は、かならず引数の最後がコールバック関数でした。 このコールバック関数の中にコードを書くことで、時間のかかる処理が終わったあとに実行する、というのが表現できました。

非同期処理 — 仕事ですぐに使えるTypeScript ドキュメント

コールバック難を克服するためにPromise

以前はJavaScriptで数多くの非同期処理を実装しようとすると、多数のコールバック関数を扱う必要があり、以前はコールバック地獄と揶揄されていました。 その後、Promiseが登場し、ネストが1段になり、書きやすく、読みやすくなりました。 Promiseはその名の通り「重たい仕事が終わったら、あとで呼びに来るからね」という約束です。 これにより、上記のような、深いネストがされたコードを触れる必要が減ってきました。 何階層もの待ちが発生しても、1段階のネストで済むようになりました。 この Promise の実装は、文法の進化に頼ることなく、既存のJavaScriptの文法の上で実装されたトリックで実現できました。 コミュニティベースで実現されたソリューションです。 この Promise は現在も生き続けている方法です。直接書く機会は減ると思いますが、 Promise について学んだことは無駄にはなりません。

非同期処理 — 仕事ですぐに使えるTypeScript ドキュメント

関連記事

thenとasync awaitを比較してみた - diadia

以下おまけ(axiosを使わない方法を調べてみた)

同期処理のコード例

var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;

var xhr = new XMLHttpRequest();
var method = "GET";
var url = new URL("https://api.coindesk.com/v1/bpi/currentprice.json");
var responseObj = null;
// 第3引数をfalseすると同期処理になる
xhr.open(method, url, false);

console.log('send前のコンソールログ')
xhr.send();
if (xhr.status != 200) {
    console.warn(xhr.status)
    responseObj = xhr.responseText
} else {
    console.warn(xhr.status)
    console.warn(xhr.responseText)
}
console.log('send後のコンソールログ')
// 上記スクリプト実行結果

send前のコンソールログ
200
{"time":{"updated":"May 12, 2021 02:59:00 UTC","updatedISO":"2021-05-12T02:59:00+00:00","updateduk":"May 12, 2021 at 03:59 BST"},"disclaimer":"This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org","chartName":"Bitcoin","bpi":{"USD":{"code":"USD","symbol":"&#36;","rate":"57,175.3478","description":"United States Dollar","rate_float":57175.3478},"GBP":{"code":"GBP","symbol":"&pound;","rate":"40,487.4075","description":"British Pound Sterling","rate_float":40487.4075},"EUR":{"code":"EUR","symbol":"&euro;","rate":"47,114.4877","description":"Euro","rate_float":47114.4877}}}
send後のコンソールログ

非同期処理のコード

// https://ja.javascript.info/xmlhttprequest
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;

var xhr = new XMLHttpRequest();
var method = "GET";
var url = new URL("https://api.coindesk.com/v1/bpi/currentprice.json");
var responseObj = null;
// 第3引数をtrueすると同期処理になる
xhr.open(method, url, true);

xhr.onload = function() {
  console.log("ON_LOADを実行")
};

xhr.onerror = function() { 
  console.log("ON_ERRORを実行")
};

console.log('send前のコンソールログ')
xhr.send();
console.log('send後のコンソールログ')
// 結果

send前のコンソールログ
send後のコンソールログ
ON_LOADを実行

thenとasync awaitを比較してみた

javascriptで非同期処理を行う場合にcallbackを使用してきた歴史がある。しかし非同期処理を使う際にcallbackを多用する場合がありコードが読みにくくなる問題が生じた。
こうした背景のもと問題解決のためPromiseという概念を発明した。

then, async awaitはこのPromiseオブジェクトに対して非同期処理の細かな制御を実現するために使うツールだと今のところ認識している。

どちらの方法でも非同期処理を制御できるけれども両者を比較したことがなかったが今回比較した。 自分の進歩を残すという趣旨で記録しているのでこの件もメモとしてのこす。

thenを使うケース

const axios = require('axios');

function createClient() {
    const client = axios.create({
            baseURL: 'https://api.coindesk.com',
            responseType: 'json'
    });
    console.log("clientを作成")
    return client
}

function getData() {
    const client = createClient();
    console.log("getData()内のrequest前のコンソールログ")
    // https://jp.vuejs.org/v2/cookbook/using-axios-to-consume-apis.html
    let chartName = null;
    client.get(url = '/v1/bpi/currentprice.json').then((response) => {
        chartName = response.data["chartName"]
        console.log(chartName)
        console.log("getData()内にあるthen内のchartName取得後のコンソールログ")
    })
    console.log("getData()内のrequest後のコンソールログ", chartName)
}


// // コードを実行
console.log("getData()前のコンソールログ")
getData();
console.log("getData()後のコンソールログ")
// 結果
getData()前のコンソールログ
clientを作成
getData()内のrequest前のコンソールログ
getData()内のrequest後のコンソールログ null
getData()後のコンソールログ
Bitcoin
getData()内にあるthen内のchartName取得後のコンソールログ

thenを使うケースにおける非同期処理のポイント

非同期処理、例えば通信後のデータを使って何かロジックを組み立てる処理には、必ずthenのスコープ内でものを書いていく必要がある。

thenを使うケースにおける同期処理の優先順位

同期処理の優先順位つまり非同期処理を除いたロジックの流れは、以下の流れになると推測する。

非同期処理を含む関数(getData)では非同期処理以外(thenスコープ外)の命令が上から順番に実行される。これでgetDataが終わったとみなされ、その後に続く関数console.log("getData()後のコンソールログ")が実行される。getData内の非同期処理は同期処理とは無関係に、(マイペースに、)非同期処理の原因となる遅い処理が終わると、その後に続く処理console.log(chartName)console.log("getData()内にあるthen内のchartName取得後のコンソールログ")が実行されていく。

async, awaitのケース

const axios = require('axios');


function createClient() {
    const client = axios.create({
            baseURL: 'https://api.coindesk.com',
            responseType: 'json'
    });
    console.log("clientを作成")
    return client
}
 
async function getData() {
    const client = createClient();
    console.log("getData()内のrequest前のコンソールログ")
    // https://jp.vuejs.org/v2/cookbook/using-axios-to-consume-apis.html
    const response = await client.get(url = '/v1/bpi/currentprice.json')
    const chartName = response.data["chartName"]
    console.log(chartName)
    console.log("getData()内のrequest後のコンソールログ")
};

// コードを実行
console.log("getData()前のコンソールログ")
getData();
console.log("getData()後のコンソールログ")
// 結果
getData()前のコンソールログ
clientを作成
getData()内のrequest前のコンソールログ
getData()後のコンソールログ
Bitcoin
getData()内のrequest後のコンソールログ

async, awitを使うケースにおける非同期処理のポイント

thenの場合ではthen内の処理がすべて非同期になるのに対し、async, awaitのケースの場合asyncがついた関数の処理すべてが非同期になるわけではない感じがする。async内のawait以降に書かれる処理がすべて非同期になり、await以前は同期処理扱いになるのではないかと推定する。

Inside the async function we can use await. JavaScript will know to execute the rest of the code only after the awaited function is resolved.

Promises in JavaScript: Explained for Kids | by ALEXANDRU TAPIRDEA | Apr, 2021 | Level Up Coding