始めに
javascript学習中であり、学習様にまとめます。非同期処理の仕組みを振り返り、promise、async awatを学習していきます。
同期処理 非同期処置
-
同期処理
-
メインスレッドでコードが順々に実行される。
-
1つの処理が終了しないと、次の処理へ移行しない。
-
本来処理はコールスタックに積まれていきその積まれたスタック(実行中のコードのコンテキスト)がlast in first outの原則で処理がスタックがはけていく。
-
非同期処理
-
同期処理は処理が実行されるまで次の処理が移行しないが、非同期処理を行うことで、処理をメインスレッドから分離ができる。
-
この分離している期間を利用して、次の同期的処理を実行できると言うことだ。
-
分離された処理が全てのコールスタックがはけて、戻ってこれる。
タスクキュー
- 実行待ちの非同期処理の行列
- 非同期処理の実行順はfirst in first outの原則からキューの中に入ってきた処理順に実行される
非同期処理の例
setTimeoutは一般的な非同期処理である
ここでのconsole.logの実行中を見ると、test()を実行した段階で、setTimeoutによって処理の分離が行われる。そしてtest2が実行。そして、次のコンテキストに移り、test3が実行。
test3が実行された段階で、キューからコールスタックに切り離された処理が戻り、task3が実行される。
//非同期処理の例
const test = () => {
setTimeout(() => {
console.log("test1");
}, 4000);
console.log('test2');
};
const test2 = () => {
console.log('test3');
}
test();
test2();
//console.logの表示順
test2->test3->test
非同期処理のチェーン
非同期処理はチェーンできるが、繋げれば繋げるほど可読性が悪くなる
const test = (callback, val) => {
setTimeout(() => {
console.log(val++);
callback(val);
}, 1000);
};
test((val) => {
test( (val) => {}, val)
}, 1);
その為作られたのがpromise
Promise
- 非同期処理を簡単に書ける様にした仕組み
- 非同期処理を操作できるオブジェクト。
- promiseの引数として、resoleve, rejectをとることができる。
- promiseは.thenメソッドでチェーンとして処理をつなげることができる
- サーバーに繋ぐ .then データを取得します .then データを取得したら処理をします。と言う具合に処理を繋げることができる。
- 状態とはresolve(ok)、reject(ng)として受け取ることができる。
構文としては
//Promiseはコールバックをとる。その引数にresolve、rejectをとることができる。
const test = new Promise((resolve, reject) => {
//同期処理
}).then(() => {
//非同期処理(resolveを待つ)
}).catch( () => {
//非同期処理(rejectを待つ)
}).finally( () => {
//非同期処理
})
then()メソッドの記述
const test = new Promise((resolve, reject) => {
//引数で受け取ったresolveを使用する。
resolve("hello");
}).then((data) => {
//resoleve()の引数がthen()の引数となる。
console.log(data);
});
//catchの場合
const test = new Promise((resolve, reject) => {
reject("test");
})
.then((data) => {
console.log(data);
})
.catch((data) => {
console.log(data)
//次then()にdataを渡す場合
return data;
}).then( (data) => {
console.log(data);
});
console.log("globle test");
→結果: globle test, test
//rejectはPromiseで渡すコールバックでしか使用できないので、then()なで処理の分岐をする場合はthrow new Errorで処理の分岐を行う
const test = new Promise((resolve, reject) => {
reject("test");
})
.then((data) => {
console.log(data);
throw new Error()
})
.catch(() => {
console.log("error catch");
});
console.log("globle test");
結果:globle test , error catch
Promiseチェーン
promiseを使用して複数の非同期処理を実行する。
const testPromise = (val) => {
return new Promise((resolve) => {
setTimeout(() => {
console.log(val++);
resolve(val);
}, 4000);
});
};
//testPromiseを実行してタイミングで戻り値としてpromise関数が返却されるのでthen()が使用できる
testPromise(0)
//ここの引数のvalはtestPromise関数の引数であるval
//なぜvalの値が0にならにかと言うと、処理を連続して繋げているから
.then((val) => {
return testPromise(val);
})
.then((val) => {
//return で必ずPromiseのインスタンスを返さないと処理が切れてしまう。
return testPromise(val);
});
Aysnc Await
Pomiseをさらに直感的に書ける様にした仕組み
Async
- promiseを返却する関数を宣言する。関数の前にaysncをつける
Await
- promiseを返却する関数の非同期処理が実行されるまで待つ。
- 処理が実行されたら次の処理に移る
実際のコード
const testPromise = (val) => {
return new Promise((resolve) => {
setTimeout(() => {
console.log(val++);
resolve(val);
}, 4000);
});
};
//asyncで宣言を行う
const test = async () => {
//awaitで非同期処理が完了するまでまつ。その結果を変数に代入する
let val = await testPromise(0);
console.log(val);
};
test();
//処理を繋げることも可能
const test = async () => {
let val = await testPromise(0);
val = await testPromise(val);
val = await testPromise(val);
val = await testPromise(val);
val = await testPromise(val);
};
test();
Promiseを使用しているのでもちろんthen()を使用できる.
const testPromise = (val) => {
return new Promise((resolve) => {
setTimeout(() => {
console.log(val++);
resolve(val);
}, 4000);
});
};
const test = async () => {
let val = await testPromise(0);
val = await testPromise(val);
return val;
};
//test()でもpromiseの処理の後にthen()が実行される
test().then(() => {
console.log("hello" + val);
});
error catchもできる
const testPromise = (val) => {
return new Promise((resolve) => {
setTimeout(() => {
console.log(val++);
resolve(val);
}, 4000);
});
};
const test = async () => {
let val = await testPromise(0);
val = await testPromise(val);
throw new Error();
return val;
};
test()
.then((val) => {
console.log("hello" + val);
})
.catch((e) => {
console.log(e);
});
try catch
promiseチェーンで処理を繋げて,exceptionがあれば.catchでエラーを出力していたが、try , catch文でも同様のことができる。
import React, {useState, useEffect} from 'react'
import axios from 'axios';
const User = () => {
const [user, setUser] = useState({});
const getUser = async () => {
try {
const res = await axios.get('api_path');
setUser(resd.data);
} catch(err) {
console.log(err);
}
}
useEffect(() => {
getUser();
}, [])
}
終わりに
非同期処理を学習しました。次ぎはtry catchを追加していこうと思います。