diadia

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

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":"$","rate":"57,175.3478","description":"United States Dollar","rate_float":57175.3478},"GBP":{"code":"GBP","symbol":"£","rate":"40,487.4075","description":"British Pound Sterling","rate_float":40487.4075},"EUR":{"code":"EUR","symbol":"€","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を実行