async / await とプロミスオブジェクト
プロミスオブジェクト
JavaScript で非同期的な処理を扱うために提供されている、 Promise
API というものがあります。
Promise のインスタンスには、3つの状態があります。
pending
: 処理待ち中。処理が終わると下の2つのいずれかに移行します。fulfilled
: 処理が成功した状態。rejected
: 処理が失敗した状態。
早速 Promise を作ってみましょう。
const promise = fetch("https://www.google.com");console.log(promise);
$ bun run ./script1.tsPromise { <pending> }
プロミスの基本メソッド
Promise が fulfilled
になった後に実行するコードを登録するために、then
メソッドを使います。
const promise = fetch("https://www.google.com");
promise.then((resp) => { console.log(resp);});
$ bun run ./script2.tsResponse (7.48 KB) { ok: true, url: "http://www.google.com/", status: 200, statusText: "OK", headers: Headers { /* 省略 */ }, redirected: false, bodyUsed: false,}
Promise が rejected
になった後に実行するコードを登録するために catch
メソッドを使います。
const promise = fetch("https://not-exists.google.com");
promise.catch((err) => { console.log(err);});
$ bun run ./script3.tserror: Unable to connect. Is the computer able to access the url? path: "https://not-exists.google.com/", errno: 0, code: "ConnectionRefused"
Promise のコンストラクター
ここまでは、 Fetch API で作られた Promise オブジェクトに操作をしてきました。自分で Promise オブジェクトを作ることもできます。const p1 = new Promise((resolve, _reject) => { resolve(1);});p1.then(console.log);
const p2 = Promise.resolve(2);p2.then(console.log);
const p3 = Promise.reject(3);p3.catch(console.log);
const { promise: p4, resolve } = Promise.withResolvers();p4.then(console.log);resolve(4);
$ bun run ./script4.ts1234
async
と await
さて、お待ちかねの async
/ await
です。
async
キーワードを関数の宣言時につけることで、関数の内部で await
というキーワードが使えるようになります。
await
キーワードは、 Promise オブジェクトのような then
メソッドをもつオブジェクトの非同期な扱いを、同期関数と同じような書き方で書けるようにする糖衣構文 (Syntax Sugar) です。
async function main() { try { const res = await fetch("https://www.google.com"); console.log("got status", res.status); const json = await res.json(); console.log("got json", json); return "ok"; } catch (err) { console.log("got error", err); return "error"; }}main();
async
をつけた関数はそれ自体が Promise を返します。
console.log(main());// -> Promise { <pending> }console.log(await main());// -> "error"
await
自体にエラーハンドリングの仕組みは付属しないので、catch
メソッドに代わるものとして try ~ catch
を使います。
演習
https://jsonplaceholder.typicode.com/todos
にアクセスすると、適当な Todo を返してくれます。
Fetch API を使って、ここで返される Todo を title
で部分一致検索するような非同期関数を作ってみましょう。
解答例
async function getTodos(titleLike: string): Promise<Todo[]> { const resp = await fetch("https://jsonplaceholder.typicode.com/todos"); const todos: Todo[] = await resp.json(); return todos.filter((todo) => todo.title.includes(titleLike));}
console.log(await getTodos("fugiat"));// [// {// userId: 1,// id: 3,// title: "fugiat veniam minus",// completed: false,// }, ...// ]