質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Q&A

解決済

3回答

2213閲覧

同一プロミスにPromise.resolveを同時に複数回実行した時なぜ競合しないのか?

Kenji.Noguchi

総合スコア358

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

0グッド

0クリップ

投稿2020/06/18 05:09

編集2020/06/18 05:39

未解決のプロミスオブジェクトがあったとします。そのオブジェクトに対して同時に複数回Promise.resolveを呼び出した場合の挙動について、競合せず安全か、そして解決後の挙動は確定的かどうかが質問です。

Chromeでテストしたところ競合は起きず、またプロミスの実行は一度だけで、resolveを呼び出した順にthenが実行されているように見えます。

これはPromiseの言語仕様上当然のことですか?複数回呼び出した時のインタプリタ内部の処理の流れを教えてください。例えばPromise.resolveはpにコールバックを登録するような動きなのでしょうか。解決後は登録された順にCBを呼び出しているのだとすれば、競合が起きないのは説明がつきそうです。

実験

次のように非同期の関数を定義して実験しました。http://localhost:8081はマルチスレッドのウェブサーバーで複数のリクエストを同時に処理することが出来ます。ただし、レスポンスに5秒かかるように細工がしてあります。目的は複数の同時アクセスがあるのかの検証です。

JavaScript

1async function main() { 2 var p = fetch('http://localhost:8081'); 3 console.log(p); 4 Promise.resolve(p).then((r)=>console.log(1, r.status)); 5 console.log(p); 6 Promise.resolve(p).then((r)=>console.log(2, r.status)); 7 console.log(p); 8 Promise.resolve(p).then((r)=>console.log(3, r.status)); 9}

実行します

JavaScript

1await main()

結果

Promise {<pending>} Promise {<pending>} Promise {<pending>} # 5秒経ったのち 1 200 2 200 3 200

サーバー側のログには1行だけアクセス記録がありました。

$ ./server.py Starting server, use <Ctrl-C> to stop sleep 5 127.0.0.1 - - [17/Jun/2020 21:51:22] "GET / HTTP/1.1" 200 -

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

Promise.resolveを呼び出した場合の挙動について

そもそも論として、Promise.resolveは「引数に与えられたPromiseresolve状態にするもの」ではなく、「普通の値からresolve状態のPromiseを作成する」ための関数です。

Promise.resolvePromiseを与えた場合は、他の回答にもあるようにそのまま返ります(このような呼び出しは、意図して行う分には無意味です)。

投稿2020/06/18 05:43

編集2020/06/18 05:44
maisumakun

総合スコア145192

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2020/06/18 05:48

Promiseの外側からresolve/rejectを制御することは、(new Promiseのコールバックへ引数として与えられるresolve/reject関数を外に持ち出すような強引なことをするなら別ですが)基本的にできません。
Kenji.Noguchi

2020/06/18 06:06

なるほど。回答の本文とコメントでなぜPromise.resolveが必要なのかよく理解できました。
guest

0

もし与えられた引数の値が Promise なら、そのPromise が返されます。

Promise.resolve() - JavaScript | MDN

とのことなので、Promise.resolve(p) === pです。

投稿2020/06/18 05:35

Lhankor_Mhy

総合スコア36134

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Kenji.Noguchi

2020/06/18 05:41

なるほど!と言うことは複数回呼び出した場合は単純に.then(...).then(...).then(...)とチェーンにしただけと言うことになりますね?
Kenji.Noguchi

2020/06/18 06:27 編集

各質問についてストレートで明快な回答を頂き、疑問が解決しました。言語仕様を理解したかったのでリンク先のアルゴリズムは決定的でした。ありがとうございます。BAは僕の誤解を指摘したmaisumakunさんにの回答に付与することにしました。申し訳ありません。
guest

0

fetchを1回しか実行していないですよね?

投稿2020/06/18 05:22

yambejp

総合スコア114878

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yambejp

2020/06/18 05:23

var p = Array(3).fill(fetch('y.php')); console.log(p[0]); Promise.resolve(p[0]).then((r)=>console.log(1, r.status)); console.log(p[1]); Promise.resolve(p[1]).then((r)=>console.log(2, r.status)); console.log(p[2]); Promise.resolve(p[2]).then((r)=>console.log(3, r.status));
Kenji.Noguchi

2020/06/18 06:24 編集

質問は3回fetchを呼び出したいわけではなく、同一の未解決のプロミスを何度もresolveしても競合せず安全か、そして解決後の挙動は確定的かどうかと言うのが質問の主旨です。
maisumakun

2020/06/18 05:45

別に回答しましたが、Promise.resolveの目的が違います。
yambejp

2020/06/18 06:04

安全?の意味がわかりませんが、1回しか実行してないfetchの resolve後に参照したらpeindingにはならずfulfilledですね async function main() { var p = fetch('y.php'); console.log(p); await Promise.resolve(p).then((r)=>console.log(1, r.status)); console.log(p); await Promise.resolve(p).then((r)=>console.log(1, r.status)); console.log(p); await Promise.resolve(p).then((r)=>console.log(1, r.status)); } main();
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問