少しPromiseについて混乱されているのかもしれません。
そもそもPromiseとは何か?から説明させてください。
Promiseは「今は分からなくても後からわかる値」を表したデータです。
通常のプログラミングおいて、例えば次のようなプログラミングがあったとします。
js
1// 0 ~ nまでの和を計算する関数
2function sum(n){ return [...Array(n+1).keys()].reduce((x,y)=>x+y); }
3const data = sum(1000);
このプログラムが実行された時点で、data
に500500という数字が入っているはずです。なぜなら、sum(1000);の関数呼び出しがその計算が終わるのを待ってから、その結果をdata
に入れるからです。
この計算または処理が終るのを待つのは、たとえ、それがいくら時間かかっても待ってしまいます。
javascript
1const data = waitVeryLongTime(); //すごく長く待たないといけない関数。
2waitedProgram(); // 待たされるプログラム
いくら時間がかかろうと、処理や計算などが終わらない限り次に進めないのです。それは困りましたね。このあとの、waitedProgram()もまた、waitVeryLongTime()が終わらないと実行されないのです。たとえ、実行するのに、waitVeryLongTime()のデータが必要無かったとしてもです。
そこで、javascriptではPromiseというものを用意しました。先ほども言いました通り「今は分からなくても後からわかる値」のことです。
たとえば次のコードがあったとしましょう
javascript
1const data = returnPromiseFunc(); // Promise(今は分からなくても後からわかる値)を返す関数
2noWaitedProgram(); //またなくていい!
このreturnPromiseFunc()
はPromiseを返すとしましょう。
このときreturnPromiseFunc()
は計算や処理の途中であってもデータを返すことができます。なぜなら、Promiseは「(計算や処理の途中だから)今は分からないけど、後からわかるよ」というデータだからです。
そしてそのままreturnPromiseFunc()
は計算が途中のままのデータを返します。その途中の計算はPromiseが引き継ぎます。そして、dataがそのPromiseを受け取ります。
dataに「(途中の計算だけど)Promiseというデータが返ってきた」というので、その次のnoWaitedProgram();に進めるわけです。
さて、dataはPromiseオブジェクトが渡されました。もしPromiseの内部にある計算が終わった「後からわかるデータ」を使いたいと思ったとしましょう。でもこのままだとデータは使えません。
そこで.then()
というメソッドが出てくるわけです。
javascript
1// .thenは、Promiseの中の計算が終わった時何をやるかを記述するためのもの
2data.then((resultData)=>{
3 console.log(resultData);
4});
このように書くことによって、resultData
という引数に、「後から分かるデータ」がやってくるわけです。
また、「後から分かるデータ」は必要ないけど、そのPromiseが完了したタイミングで処理をしたいときもあるでしょうその時は、
// 終わった後のデータが要らないとき
data.then(()=>console.log("Promise resolved!"));
のように書きます。
さて、次にnew Promise((resolve)=>{})
を使うときを紹介しましょう。PromiseはもともとJavascriptには無かったものでした。Promiseが無かった時代の以前のJavascriptは、このような「今は分からないけど後で分かる」みたいな処理をコールバックを使って処理していました。
次のように書いていました。
javascript
1// 関数の引数に直接「後から分かった後の処理をする関数」を渡す
2callbackFunction((resultData)=>{ console.log(resultData); });
3
このように計算が終わった後の処理をするコールバック関数を予め渡してあげることによって、計算が終わった後のデータの処理をしていました。
何が違うかと言えば、返り値が無いのです。Promiseが無い、つまり「今は分からないけど後で分かる」というものが無いので何も返しようがないのです。もし値を返したいのであれば、計算が終わるまで待つ必要がありました。
このような関数の典型例がsetTimeout
です。
javascript
1// 1000ms後の処理をする関数を渡して、
2setTimeout(()=>{
3 /// code...
4},1000);
5noWaitProgram(); // もちろん1000ms待たなくていい
6
setTimeoutは、「計算(ただ待つというだけの処理)が途中であっても」関数を抜け出して次の処理に行きます。待つ後の処理はコールバックに任せるからです。
Javascriptにはこのような非同期のコールバックを受け取る関数によって非同期処理を書いていました。new Promise
はこようなコールバックを受け取る関数から、Promiseを返す関数にラップするのに使います。
javascript
1// setTimeoutをPromiseを返す関数にする
2function timeout(ms){
3 // promiseを作って、「今は分からないけど後から値が分かる」データをつくる
4 const promise = new Promise((resolve)=>{
5 setTimeout(()=>{
6 resovle(); // ここで値が分かる(処理が終わる)
7 }, ms);
8 });
9 // データを返す
10 return promise;
11}
12
13timeout(1000).then(()=> console.log("1000ms秒後だ"); );
これで、Promiseの基本的なこと、then
を使う基本的な意味、 new Promise((resovle)=>{})
を使うときを説明しました。
あとは、やらないといけないことはPromiseチェーンについてです。
先ほど.then
について話しました、あと大事なのは.then
自体の返り値についてです。
javascript
1data.then((resultData)=> console.log(resultData) );
と書きました。実を言えば、この式によって返されるデータもまたPromiseなのです。
javascript
1let data2 = data.then((resultData)=> console.log(resultData); );
2data2.then(()=> console.log("..."); });
上記の式でいえば、data.then()
の返り値もまたPromiseになります。なので、このPromiseもまた、thenで、「後から分かるデータ」を受けとることができます。そのデータはdata.then((resultData)=>{ ... });
でthenに渡された関数の返り値です。
例えば次のように書いたとしましょう
javascript
1const data2 = data.then((resultData)=>{ return 1; });
2data.then((resultData2)=>console.log(resultData2); });
このときにresultData2
に渡される「後から分かる」データは1になります。
更に、.then
のに渡された関数の返り値がPromiseだったとしましょう。これはそのPromiseがthenの戻り値になります
javascript
1const data2 = data.then((resultData)=>{ return 1; });
2data2.then((resultData2)=>{ return timeout(1000); });
わかりやすさのため、返り値を一旦変数に渡して、それからthen
につなげるように書いていますが、実際には、thenは必ずPromiseを返すため、このように書くことができます。
javascript
1 returnPromiseFunc()
2.then((data1)=>{
3 return data1 + 1;
4})
5.then((data2)=>{
6 return returnPromiseFunc2(data2);
7})
8.then((data3)=>{
9 console.log(data3);
10});
このようにPromiseにthenで繋げて書くことをPromiseチェーンと言います。このように書くことによって、非同期処理が(コールバックを受け取る非同期関数と比べて)書きやすくなったのです。
以上によりPromiseの基本的なことは述べました。最後に質問者の太字に答えて終わります。
resolveとreturnそれぞれの使い所、使い分け
「この使い分け」と言いますが実際には「使い分け」ということを聞くこと自体がズレているように感じます。全く別物なのです。
ただそれぞれをまとめるとこうでしょう。
Promise(()=>{})や.then(()=>{})と書いた時、左の()に引数を明記するのはどんな時か
Promiseの「後で分かる値」を次の処理に使いたいときです。
と最初に関数Aの返り値をPromiseにして、その後"A.then"と書くことがあるがそれはどのような時か?(そのように書くメリット?)
Promiseを使えるようになることです。Promiseを使うことによって、非同期処理がより書きやすくなります。
async/awaitもPromiseをベースとしています。なので、async/awaitを使う上でも、Promiseの理解があると、書きやすくなると思います。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。