95655


JavaScriptの非同期処理、Promiseを学習しています。

Promise構文において、thenメソッドの返り値は新しいPromiseインスタンスというところまでは理解できました。しかしその点を知ったことで、かえってわからなくなってしまったことがあります。

[code]

    resolvePromise = new Promise((resolve)=>{
      resolve('成功');
    })
    resolvePromise
      .then((val) => {
        console.log(val);
        return('成功2'); //★
      })
      .then((val2) => {
        console.log(val2);
      })
    
    　//結果：成功 成功2
    
[/code]

このPromiseチェーンでは最初のthen（★）でreturnを使い、  
次のthenに文字列「成功2」を渡しています。

thenメソッドの返り値は別のPromiseインスタンスですが、  
ここでreturnを使うと、返りはPromiseインスタンスではなく、  
Strings（'成功2'）になってしまうのではないかと疑問に感じました。

thenの中のreturnは糖衣構文なのでしょうか。  
技術書やPromiseについて詳しく解説されているサイトを閲覧しても  
触れられていないのですが、この点が腑に落ちません。

どなたかご教示お願い致します。


CC BY-SA 4.0
2023-07-16T10:41:01.780
95650
2023-07-17T08:38:29.243
34060
question
javascript 非同期 promise
Promiseチェーンの仕様が理解できません


[Promise.prototype.then()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)
より

> `then()` は
> [`Promise`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise)
> オブジェクトのメソッドであり、最大 2 つの引数として、 `Promise`
> が成功した場合と失敗した場合のコールバック関数を取ります。これは直ちに同等の `Promise`
> オブジェクトを返し、プロミスの他のメソッドを[連鎖](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Using_promises#chaining)呼び出し

(文章が途中で切れてる気がするけど, 原文ママ)

`.then()` メソッドから, 何らかの値を返す関数を受け取り 呼び出しても  
その値を 別の関数から直接参照したりすることはありません  
記されてる通り, **`Promise` オブジェクトを返し**ます

元の Promiseオブジェクトが値を受け取り, 新しい Promiseオブジェクトを作り出す  
チェーンに沿って実行されるだけ

[Promise.resolve()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve)
より

> `Promise.resolve()` は、ネイティブの `Promise` のインスタンスを特別扱いしています。 `value` が
> `Promise` またはそのサブクラスに属し、 `value.constructor === Promise` の場合、新しい `Promise`
> インスタンスを作成せずに、`Promise.resolve()` で直接 `value`
> を返すことができます。そうでない場合、`Promise.resolve()` は基本的に `new Promise((resolve) =>
> resolve(value))` の一括指定となります。

(`Promise.resolve()` 内部で使用してるはず)

参考:

  * [Promise](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise)
  * [Promise() コンストラクター](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise) の「典型的な流れ」辺り


CC BY-SA 4.0
2023-07-16T12:19:19.667
95651
2023-07-16T12:33:08.207
2023-07-16T12:33:08.207
43025
43025
95650
answer


>
> thenメソッドの返り値は別のPromiseインスタンスですが、ここでreturnを使うと、返りはPromiseインスタンスではなく、Strings（'成功2'）になってしまうのではないかと疑問に感じました。

前の質問者さんのスレッドで紹介した MDN の記事、

Promise.prototype.then()  
<https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then>

の「返値」のセクションに、

> 返値  
>  新しい Promise をすぐに返します。  
>  返されたプロミス（p と呼ぶ）の振る舞いは、ハンドラーの実行結果に依存し、一連の特定のルールに従います。もしハンドラー関数が、  
>  ・値を返した場合、 p は返値をその値として履行されます。

・・・と書いてある通りではないのでしょうか？

上で言う「ハンドラー」は質問者さんのコードで言うと、

[code]

    (val) => {
        console.log(val);
        return('成功2'); //★
      }
    
[/code]

なので、返された Promise は '成功2' をその値として履行と言うことになるはずです。

* * *

**【追記】**

下のコメント欄で「回答欄に追記します」と書いた件です。

自分も 100% 分かっているわけではないので想像も混じってますが、以下のようなことになっていると思います。

以下の MDN の記事の図を見てください。

Promise  
<https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise>

(1) 質問のコードにある resolvePromise が図の左端の Promise に相当

(2) resolve('成功') となっているので Promise は「履行」状態となる

(3) 図の「履行 (fulfill)」の矢印の方向に沿って進む

(4) then は新しい「待機」状態の Promise (図の左から 2 つ目の Promise) を返す

(5) 図の左端の Promise は「履行」状態なので then(onFulfilled, onRejected) の onFulfilled
ハンドラが実行される

(6) 上の (4) の Promise の状態は「履行」になる

(7) 図の右端の then 以降でも、上の (3) から (6) と同様な処理が行われる

以上は「履行」の場合ですが、「拒否」(失敗) の場合は以下のコードで試してみると動きが分かると思います。

[code]

    // 1つの resolve または reject だけを呼びだす
    let resolvePromise = new Promise((resolve, reject) => {
        //resolve('成功');
        reject('失敗');   // resolve があると無視される
    });
    
    resolvePromise.then(
        (val) => { console.log(val); return '成功2'; },
    
        // 以下のようにすると次の then では (val) => { ... } が呼び出される
        //(err) => { console.log(err); return '失敗2'; }
    
        // 以下のようにすると次の then では (err) => { ... } が呼び出される
        (err) => {
            console.log(err);
            return new Promise((resolve, reject) => {
                reject('失敗2');
            })
        }
    ).then(
        (val) => { console.log(val); },
        (err) => { alert(err); } // こちらが呼ばれれば alert が出る
    );
    
[/code]


CC BY-SA 4.0
2023-07-17T00:47:02.677
95655
2023-07-17T08:38:29.243
2023-07-17T08:38:29.243
51338
51338
95650
answer