generated at
Promise
非同期処理を統一的に扱う方法を定義したオブジェクト
型は Promise<string | undefined> みたいな感じ
非同期処理の成功時、失敗時の処理を明示的に書くことができる
非同期処理を並行、直列に実行できる
起源はE言語これらしい


Promiseの状態から考えると理解しやすい
Promiseは3つの状態を持ち、それに伴って値を保持する
pendingから
Promise.resolveすることでfulfilledになる
このときPromiseは、Promise.resolveに渡した値を保持する
この値を取得するためには、Promise.thenを呼ぶ
Promise.rejectすることでrejectedになる
このときPromiseは、Promise.rejectに渡した値を保持する
この値を取得するためには、Promise.catchを呼ぶ


何が嬉しいか?
コールバックによるネストが深くなる問題を解決
タイミング不定問題を解決
インターフェースが制限されたことでコールバックの指定の仕方がわかりやすくなった


new Promise then catch の基本について
Promise.all など





参考
使用の観点でわかりやすい
概念の理解としてわかりやすい
Promiseを再実装しているので細かいところも追える


途中まで読んだ
途中まで読んだ



ts
type Constructor<T> = ( executor: ( resolve: (value?: unknown) => void, reject: (reason?: any) => void ) => void ) => Promise<T>;
Promiseオブジェクトを生成
インスタンス生成のイメージ
2重の高階関数になっている
new Promise(fn) fn は関数
fn である (resolve, reject)=> void resolve reject も関数
new Promise((t=>void, e=>void) => void)
fn の引数となる関数
resolve(v)
処理が成功したことを表す
成功した結果として v を返す
reject(e)
処理が失敗したことを表す
err情報として、 e を返す





.finally()
成功時も失敗時も呼ばれる


throw された時
ts
new Promise<number>((resolve) => { throw new Error("err"); }).catch((err) => { console.error(`Caught by .catch ${err}`); });
rejected が呼ばれた時
ts
type User = { id: number; username: string }; const authorized = false; function getUserById(id: number) { return new Promise<User>((resolve, reject) => { if (!authorized) { reject(new Error("Unauthorized access to the user data")); } resolve({ id, username: "admin" }); }); } getUserById(10) .then((user) => console.log(user.username)) .catch((err) => console.log(`Caught by .catch ${err}`));
上2つの例では両方とも new Error() を伝達しているが別に文字列でもなんでも良いmrsekut
throwしないで、rejectしよう





実行のタイミング
Promiseを生成したタイミングで内部の処理は実行される
ただし、コールバック関数は実行されない
then() catch() が呼ばれたタイミングでコールバック関数が実行される
こんな関数を定義する
ts
const asyncFunction = () => { console.log("1"); return new Promise((resolve, reject) => { console.log("2"); setTimeout(() => { console.log("3"); resolve("Promise Hello world"); console.log("4"); }, 16); }); };
thenを呼ばないと、コールバック関数は実行されない
result
asyncFunction(); $ ts-node src/index.ts 1 2 3 4
当たり前だが、こう書いても全く同じ挙動になるよ
ts
const r = asyncFunction(); // 1,2,3,4は実行される
thenを呼ぶとコールバック関数が実行される
result
asyncFunction().then(v => console.log(v)); $ ts-node src/index.ts 1 2 3 4 Promise Hello world

resolveの引数を複数にしても捨てられる?
then節の関数を複数にしても型エラー、実行時エラーになる
ts
new Promise((resolve: (arg: number, str: string, n: boolean) => void) => { setTimeout(() => { resolve(10, "hoge", true); // ここの"hoge", trueはどこに行く? }, 16); });
thenなどの結果を変数に束縛できない?
ts
const asyncFunction = () => new Promise<number>(resolve => { setTimeout(() => { resolve(10); }, 16); }); const str = asyncFunction() .then(value => value + 20) .then(value => value + 30) .catch(error => { console.log(error); }); console.log(str) // 60...というふうにしたい。
↑では、strの型は Promise<number|undefiend> になっている
むり?そもそもそういうのが欲しくなるニーズがない?








cansel


自作


Promiseの拡張ライブラリがある




then節のチェーンは、「普通は」毎回新しいPromiseを返すような書き方をする?
普通の値も返すこともある?
それぞれのユースケースを知りたい
A. 実用的な例
fetchAPIはPromiseを返し、その返り値に含まれる .json() もまたPromiseを返す
ts
fetch("http://example.com/movies.json") .then(response => response.json()) .then(json => console.log(json)) .catch(err => console.log(err));
ちなみにこのコードはnodeではなくブラウザ上でないと動かない

ts
const doubleE = (data: number): Promise<number> => new Promise((f, e) => { setTimeout(() => { if (Math.random() < 0.3) { e(new Error("ERROR!")); } else { f(data * 2); // こことかを、`return f(data*2)`にしたときとの違い } }, Math.random() * 1000); });






Promiseは入れ子にしても二重になるわけではない
js
console.log( Promise.resolve( Promise.resolve( Promise.resolve(1) ) ) ) //=> Promise { 1 }











deepdive


PromiseによるJavaScript非同期処理レシピ集