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

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

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

npmは、Node Packaged Modulesの略。Node.jsのライブラリ・パッケージを管理できるツールです。様々なモジュールを簡単にインストールでき、自分でモジュールを作成し公開する際にも使用できます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

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

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

Q&A

9回答

609閲覧

非同期通信でレスポンスがあったものを指定の順番に出力するロジック

退会済みユーザー

退会済みユーザー

総合スコア0

npm

npmは、Node Packaged Modulesの略。Node.jsのライブラリ・パッケージを管理できるツールです。様々なモジュールを簡単にインストールでき、自分でモジュールを作成し公開する際にも使用できます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

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

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

0グッド

0クリップ

投稿2017/11/19 11:17

編集2022/01/12 10:55

以下のコードを用いてライブラリやPromiseなどを使わずに、5つのurlに対して次々にほぼ同時にリクエストを送って、「1.txt、2.txt、3.txt、4.txt、5.txt」と指定した順番にレスポンス結果を出力し、最後に「all done!」と出力する為には、みなさんならどのような書き方をしますか?

注意点としては、1つの目のリクエストのレスポンスを受けた後に、次のリクエストを送るといった順列処理ではなく、最初に5つのリクエストをほぼ同時に行って、指定の順序でレスポンスを出力するというところです。

補足:KSwordOfHasteさんの回答にあったように、**「結果が揃っている部分だけはできるだけ早く(しかし順番を守って)処理したい」**という想定です。

また、以下に掲載するコードを使ってください。どうしても使いたくない場合は、それはそれでOKとします。。。以下の掲載コードにある関数外にコードを書くのはOKです。

また、前述の通り、ライブラリやPromiseなどを使うのはNGとします。

尚、自分も後で自分なりのやり方を投稿しますが、やり方を教えて欲しいといった類の質問ではなく、どういったやり方をみなさんがされるかに興味があるため、「コードを載せてください」といった趣旨に沿わないコメントは不要です。

JavaScript

1// ajaxのフェイクバージョンのつもり 2function fakeAjax(url, callback){ 3 //レスポンスまでのランダムなタイムラグをシミュレート 4 var time = Math.floor(Math.random()*(3000-1000)+1000); 5 var responseMock = { 6 "1.txt": "1st request", 7 "2.txt": "2nd request", 8 "3.txt": "3rd request", 9 "4.txt": "4th request", 10 "5.txt": "5th request" 11 }; 12 setTimeout(() => { 13 callback(responseMock[url]); 14 }, time); 15} 16 17function getFile(url){ 18 fakeAjax(url, function(response){ 19 // 20 }); 21} 22 23getFile("1.txt"); 24getFile("2.txt"); 25getFile("3.txt"); 26getFile("4.txt"); 27getFile("5.txt");

期待するログ出力の結果(console.log)

1st request 2nd request 3rd request 4th request 5th request all done!

補足

低評価を押す場合は理由を添えてください。マイナス評価が多いにも関わらず、質問の趣旨に沿った物凄く有益な回答を頂いており、価値あるページになっていると思います。あえて、質問の趣旨に意図的に沿わない回答をする必要はないかと思いますので、的外れな回答はお控えください。

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

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

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

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

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

maisumakun

2017/11/19 13:26

質問でない「ご意見募集」的なものについてはteratailの守備範囲でないと、タグ追加希望に対してメールが帰って来たことがありました。
退会済みユーザー

退会済みユーザー

2017/11/20 14:04

ありがとうございます。
yambejp

2017/11/22 09:11

で、結局ご自身のソースは載せないのでしょうか?
退会済みユーザー

退会済みユーザー

2017/11/23 14:27

中の人に非推薦の質問と指摘されたので削除依頼を出そうかと思いまして。
yambejp

2017/11/24 12:59

ここまで広げたら削除するのはどうかと思いますよ・・・最初の約束通りご自身の解を提示してBAなしでいいのでクローズしてください
退会済みユーザー

退会済みユーザー

2017/11/25 10:10

いや、中の人に非推薦と言われたので削除が妥当なのかなと思いまして。
Lhankor_Mhy

2017/11/27 05:04

削除依頼の結果はいかがでしたか? 削除されるのであれば、他のユーザーがこの質問を見て回答を考えるリソースが無駄ですので、お早めに。……とはいえ、仕様上、-6の評価の質問がフィードに載ることはあまりない( https://teratail.com/blog/article/ba22#-1 )でしょうから、現実的にはその心配はないでしょうけれど。
guest

回答9

0

そもそもteratailは有益な情報を共有する場であって、
質問者のためのオーダメイドのコードを書く場とは違います。
低評価が付いてるのも、そういう理由からだと思います。

実務では「ライブラリやPromise」を素直に使えば良いと思います。
ただ、それ以外の方法もあるので、一応書いてみました。

上記の理由で、ご質問の細かい仕様はあえて無視し、
不特定多数で共有しやすいように、シンプルに書きました。


javascript

1function fakeAjax(g) { 2 var time = Math.floor(Math.random() * 2000 + 1000); 3 setTimeout(function() { 4 console.log(g.next()); 5 }, time); 6} 7 8var g = (function*() { 9 yield "1st request"; 10 yield "2nd request"; 11 yield "3rd request"; 12 yield "4th request"; 13 yield "5th request"; 14 return "all done!"; 15})(); 16 17for (i = 0; i < 6; i++) { 18 fakeAjax(g); 19}

ほぼES6前提ですが、「Generator」を使うと、
コールバック地獄のような深いネストを避けて、
非同期処理を非常にシンプルに書くことができます。

なお余談ですが、RubyやPythonをやっていると、
「yield」や「Generator」のような概念は馴染み深いです。

投稿2017/11/19 12:37

LLman

総合スコア5592

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

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

退会済みユーザー

退会済みユーザー

2017/11/19 12:47 編集

ご回答ありがとうございました。Generatorもasync awaitもObservableもNGと書いておけばよかったです。。。まさかGeneratorを使ってくるとはw それらを使えば簡単にかけてしまうのは分かってるのですが、あえてというところです。
退会済みユーザー

退会済みユーザー

2017/11/19 12:43

teratailが有益な情報を共有する場であるならば、なんの問題もないと思うのですが、感情的に気にくわない類の内容なんでしょうね。
maisumakun

2017/11/19 13:28

上のコメントとも関連しますが、teratailはあくまで「質問する方の問題解決」の場だ、とのことです。
LLman

2017/11/19 14:03

>teraterakunさん >maisumakunさん コメントありがとうございます。 質問への低評価の理由を推測すると、 Promiseなどを禁じ手にする動機が不明で、 個人的なこだわりに思えるからだと思います。 回答者の方の具体的な問題解決を通じて、 有益な情報をみんなで共有できるのが理想です。 それで、Generatorは共有できそうなので書きました。
退会済みユーザー

退会済みユーザー

2017/11/19 14:30

このgeneratorの簡易サンプルは前のリクエストのレスポンスが返ってきたら、次のリクエストを投げるというサンプルですか?それとも、掲題の仕様を一応、想定してのものでしょうか?
LLman

2017/11/19 15:13 編集

後者です。前のレスポンスを待ってないですよ。 ジェネレータで非同期処理に対応可能です。
退会済みユーザー

退会済みユーザー

2017/11/20 00:51

その場合はGeneratorを使うにしても、質問の要件を満たしていることがわかるように最低限書いて頂きたかったです。さすがに高評価トップは他の回答者様に申し訳なくないですか?
guest

0

つまり、変なコード書いた奴が一等賞ってことですね!
負けないぞう!

javascript

1function fakeAjax(url, callback){ 2 //レスポンスまでのランダムなタイムラグをシミュレート 3 var time = Math.floor(Math.random()*(3000-1000)+1000); 4 var responseMock = { 5 "1.txt": "1st request", 6 "2.txt": "2nd request", 7 "3.txt": "3rd request", 8 "4.txt": "4th request", 9 "5.txt": "5th request" 10 }; 11 setTimeout(() => { 12 callback(responseMock[url]); 13 }, time); 14} 15 16function getFile(url){ 17 q[url] = null; 18 fakeAjax(url, function(response){ 19 q[url] = response; 20 [...q].forEach( x => console.log(x) ); 21 }); 22} 23 24const q = new Proxy([],{ 25 get: function(obj, prop) { 26 if (prop===Symbol.iterator) { 27 if (obj.length) return function*(){ 28 let x; 29 while( x = obj.shift() ) { 30 if (x.v) 31 yield x.v 32 else { 33 obj.unshift(x); 34 break; 35 } 36 } 37 if (!x) yield 'all done!'; 38 }; 39 } 40 return obj.filter( x => x.k == prop )[0].v; 41 }, 42 set: function(obj, prop, value){ 43 let entry = obj.filter( x => x.k == prop )[0]; 44 if (entry) 45 entry.v = value 46 else 47 obj.push({k:prop, v:value}); 48 }, 49}); 50 51getFile("1.txt"); 52getFile("2.txt"); 53getFile("3.txt"); 54getFile("4.txt"); 55getFile("5.txt");

不要と思いますが解説。
[{k:'1.txt', v:'1st request'}, ...]のような構造体を作り、Proxyにより独自アクセサを設定することによって、順序型であることを意識せずにプロパティにアクセスするようにしました。
また、Symbol.iteratorgetterに出力の際のめんどくさい処理を設定することにより、列挙するだけで出力が得られるようになっています。
その結果、元コードに追加したのは3行のみ、というシンプルなコードになったと思います。
(Falsyな値が来るといろいろバグりますけど)

投稿2017/11/20 09:57

編集2017/11/20 11:07
Lhankor_Mhy

総合スコア35865

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

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

退会済みユーザー

退会済みユーザー

2017/11/20 14:05

ご回答ありがとうございます。変なコードを他の回答者様は書いてるつもりはないかと思います。
Lhankor_Mhy

2017/11/20 16:02

いや、あの、実用性のない趣味に走ったコード、という意味ですよ。 コードゴルフみたいなものでしょ?
yambejp

2017/11/21 05:30

まぁ大喜利ですよね
guest

0

maisumakunさんやLLmanさんのおっしゃることはもっともであると思いましたが、Javascriptの練習のつもりでやってみました。

本件に特化した単純な実装を想定すると、Promise.all(...).then(...)でthenのところで、全ての結果を出力するようなものの特化版(下記)をイメージしましたが、

リスト1:

javascript

1const dbg = m => console.log('information: ' + m); 2 3function fakeAjax(url, callback){ 4 var time = Math.floor(Math.random()*(300-100)+100); 5 var responseMock = { 6 "1.txt": "1st request", 7 "2.txt": "2nd request", 8 "3.txt": "3rd request", 9 "4.txt": "4th request", 10 "5.txt": "5th request" 11 }; 12 13 setTimeout(() => { 14 dbg('completed ' + url); 15 callback(responseMock[url]); 16 }, time); 17 dbg('submitted ' + url); 18} 19 20function getFiles(urls) { 21 var n = urls.length, res = new Array(n), 22 i, responseCount = 0; 23 for (i in urls) { 24 getFile(i, urls[i]); 25 } 26 27 function getFile(i, url) { 28 fakeAjax(url, function (response) { 29 res[i] = response; 30 if (++responseCount >= n) 31 allDone(); 32 }); 33 } 34 35 function allDone() { 36 var i; 37 for (i in urls) { 38 console.log(res[i]); 39 } 40 console.log("all done!"); 41 } 42} 43 44getFiles(["1.txt", "2.txt", "3.txt", "4.txt", "5.txt"]);

しかしこれだとPromise.allを使わない根拠がない気がしたので、「結果が揃っている部分だけはできるだけ早く(しかし順番を守って)処理したい」という想定を置くと

リスト2:

javascript

1// fakeAjaxは省略 2// 若干の見易さのためにES2015の文法を用いました 3 4class AsyncContext { 5 constructor() { 6 this.acceptable = true; 7 this.q = []; 8 } 9 10 getFile(url, postProcess) { 11 if (!this.acceptable) 12 throw new Error('submitting queue has already been closed'); 13 const task = { postProcess: postProcess }; 14 this.q.push(task); 15 fakeAjax(url, result => { 16 task.result = result; 17 this.doPostProcess(); 18 }); 19 } 20 21 doPostProcess() { 22 while (this.q.length > 0 && this.q[0].hasOwnProperty('result')) { 23 const task = this.q.shift(); 24 task.postProcess(task.result); 25 if (!this.acceptable && this.q.length === 0) 26 console.log('all done!'); 27 } 28 } 29 30 close() { 31 this.acceptable = false; 32 this.doPostProcess(); 33 } 34} 35 36const ctx = new AsyncContext(); 37 38[ 39 "1.txt", 40 "2.txt", 41 "3.txt", 42 "4.txt", 43 "5.txt" 44].forEach(url => ctx.getFile(url, console.log)); 45ctx.close();

質問のコードテンプレートだとgetFileが必要とするコンテキストを関数の外側に用意しなければならないためそれは断念しコンテキスト保持のためのオブジェクトを用いました。

なお起動する非同期処理は決め打ちにもかかわらず後処理だけctx.getFileの引数にしている点は中途半端かつ機能分離がイケテナイ気がしました。このようなものを書くならfakeAjaxと機能を明確に分離すべきかも知れません。

投稿2017/11/19 22:34

編集2017/11/20 00:31
KSwordOfHaste

総合スコア18392

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

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

退会済みユーザー

退会済みユーザー

2017/11/20 00:29 編集

ご回答ありがとうございます。 >「結果が揃っている部分だけはできるだけ早く(しかし順番を守って)処理したい」という想定 こちらの想定で合っております。後ほど興味深く拝見させて頂きます。取り急ぎお礼まで。
guest

0

一切ライブラリのない、純粋なJavaScriptでは実装不可能です。

「JavaScript+言語標準で存在するオブジェクト」では、通信機能もタイマー機能もありません。

投稿2017/11/19 13:30

maisumakun

総合スコア145121

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

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

KSwordOfHaste

2017/11/20 02:49 編集

蛇足と思いますが、気になるのでコメントさせていただきます。本件について自分は「ひょっとするとこの想定があるかも」と気づきましたが、それはどちらかと言えば他の回答から得たところが大きく残念ながら質問文から明確に受け取ることはできませんでした。現在の質問文は当初に対し前提をより明確にしておられますが、それはmaisumakunさんや他の方の(課題・前提が不明瞭という)示唆が当を得ていた気がしました。 --- えと、これは質問者さんへのコメントです。わかりにくくなってしまいましたが・・・
guest

0

非同期でうけとって、与えた順にソートしなおしてから表示すればいいのでは?

javascript

1var a=["1.txt","2.txt","3.txt","4.txt","5.txt"]; 2var b=[]; 3for(var i=0;i<a.length;i++){ 4 getData(i,a[i]); 5}; 6var timerId=setInterval(function(){ 7 if(b.length==a.length){ 8 clearInterval(timerId); 9 var c=b.sort(function(x,y){return x[0]>y[0];}); 10 for(var i=0;i<c.length;i++){ 11 console.log(c[i][1]); 12 } 13 console.log("all.done"); 14 } 15},100); 16function getData(num,url){ 17 var xhr = new XMLHttpRequest(); 18 xhr.open( "GET", url ); 19 xhr.onreadystatechange=function(){ 20 if(( xhr.readyState == 4 ) && ( xhr.status == 200 )){ 21 b.push([num,xhr.response]); 22 } 23 } 24 xhr.send( '' ); 25}

追記

※遅延を発生させるため、読み込むファイルはphpを指定してあります

javascript

1var a=["1.php","2.php","3.php","4.php","5.php"]; 2var b=a.map(function(){return null}); 3for(var i=0;i<a.length;i++){ 4 getData(i,a[i]); 5}; 6var pointer=0; 7var counter=0; 8var timerId=setInterval(function(){ 9 while(b[pointer]!==null){ 10 console.log(b[pointer]); 11 pointer++; 12 if(pointer>=b.length){ 13 console.log("all.done!"); 14 clearInterval(timerId); 15 break; 16 } 17 } 18 counter++; 19 if(counter>100){ 20 console.log("stop!"); 21 clearInterval(timerId); 22 } 23},100); 24function getData(num,url){ 25 var xhr = new XMLHttpRequest(); 26 xhr.open( "GET", url ); 27 xhr.onreadystatechange=function(){ 28 if(( xhr.readyState == 4 ) && ( xhr.status == 200 )){ 29 b[num]=xhr.response; 30 } 31 } 32 xhr.send( '' ); 33}
  • 1.php

PHP

1<?PHP 2echo 1; 3?>
  • 2.php

PHP

1<?PHP 2sleep(3); 3echo 2; 4?>
  • 3.php

PHP

1<?PHP 2sleep(2); 3echo 3; 4?>
  • 4.php

PHP

1<?PHP 2sleep(4); 3echo 4; 4?>
  • 5.php

PHP

1<?PHP 2echo 5; 3?>

投稿2017/11/20 01:13

編集2017/11/21 05:27
yambejp

総合スコア114572

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

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

退会済みユーザー

退会済みユーザー

2017/11/20 14:07

これだと全てを受け取った後に初めて出力する形になりませんか?Promise.allみたいな。
yambejp

2017/11/20 14:16

すみません、仕様がいまいち理解できません 1から5の順で表示したいけど、非同期で同時に読みたいんですよね? たとえば4.txtが遅い場合、1,2,3は先に表示して、5は、またしておくってことですかね?
退会済みユーザー

退会済みユーザー

2017/11/20 14:34

はい、その通りでございます。
yambejp

2017/11/21 05:31 編集

ご指定の内容に併せました (非同期でよみつつ、先頭から順番に読み終わったものから表示する)
guest

0

1

イメージ説明
アニメーションGIF

JavaScript

1 2const fakeAjax = (fileName, callback) => { 3 const MAX = 5000; 4 const MIN = 1000; 5 const delay = Math.floor(Math.random() * (MAX - MIN) + MIN); 6 7 const responseMockData = { 8 "1.txt": "1st request", 9 "2.txt": "2nd request", 10 "3.txt": "3rd request", 11 "4.txt": "4th request", 12 "5.txt": "5th request" 13 }; 14 setTimeout(() => { 15 callback(responseMockData[fileName]); 16 }, delay); 17} 18 19const output = console.log.bind(this); 20 21const getFile = (fileName) => { 22 fakeAjax(fileName, (response) => { 23 handleResponse(fileName, response); 24 }); 25} 26 27const STATUS = Object.freeze({ 28 WAITING: Symbol('waiting'), 29 RECEIVED: Symbol('received'), 30 RENDERED: Symbol('rendered') 31}); 32 33 34const responseItems = new Map([ 35 ["1.txt", { status: STATUS.WAITING, content: ''}], 36 ["2.txt", { status: STATUS.WAITING, content: ''}], 37 ["3.txt", { status: STATUS.WAITING, content: ''}], 38 ["4.txt", { status: STATUS.WAITING, content: ''}], 39 ["5.txt", { status: STATUS.WAITING, content: ''}] 40]); 41 42const handleResponse = (fileName, response) => { 43 44 if (responseItems.get(fileName).status === STATUS.WAITING) { 45 responseItems.get(fileName).status = STATUS.RECEIVED; 46 responseItems.get(fileName).content = response; 47 } 48 49 for (const key of responseItems.keys()) { 50 51 if (responseItems.get(key).status === STATUS.RECEIVED) { 52 output(responseItems.get(key).content); 53 responseItems.get(key).status = STATUS.RENDERED; 54 } else if(responseItems.get(key).status === STATUS.RENDERED) { 55 continue; 56 } else { 57 return; 58 } 59 60 }; 61 62 console.log('all done!') 63 64}; 65 66 67getFile("1.txt"); 68getFile("2.txt"); 69getFile("3.txt"); 70getFile("4.txt"); 71getFile("5.txt"); 72 73

#2
イメージ説明
アニメーションGIF

const fakeAjax = (fileName, callback) => { const MAX = 5000; const MIN = 1000; const delay = Math.floor(Math.random() * (MAX - MIN) + MIN); const responseMockData = { "1.txt": "1st request", "2.txt": "2nd request", "3.txt": "3rd request", "4.txt": "4th request", "5.txt": "5th request" }; setTimeout(() => { callback(responseMockData[fileName]); }, delay); } const output = console.log.bind(this); const getFile = (fileName) => { let memoizedResult; let memoizedCallback; fakeAjax(fileName, (response) => { if (memoizedCallback) { return memoizedCallback(response); } memoizedResult = response; }); return (callback) => { if (memoizedResult) { return callback(memoizedResult); } memoizedCallback = callback; }; } const getFile1 = getFile('1.txt'); const getFile2 = getFile('2.txt'); const getFile3 = getFile('3.txt'); const getFile4 = getFile('4.txt'); const getFile5 = getFile('5.txt'); getFile1(resultForFile1 => { output(resultForFile1); getFile2(resultForFile2 => { output(resultForFile2); getFile3(resultForFile3 => { output(resultForFile3); getFile4(resultForFile4 => { output(resultForFile4); getFile5(resultForFile5 => { output(resultForFile5); output('all done!'); }) }) }) }) })

投稿2017/11/19 14:53

編集2017/11/23 10:24
HayatoKamono

総合スコア2415

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

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

退会済みユーザー

退会済みユーザー

2017/11/20 00:29 編集

ご回答ありがとうございます。後ほど興味深く拝見させて頂きます。取り急ぎお礼まで。
guest

0

ゴチャゴチャしたコードになってしまいましたが...。

lang

1const urls = ["1.txt", "2.txt", "3.txt", "4.txt", "5.txt"] 2const buffers = urls.map(url => { 3 const buffer = {done: false, result: undefined, onComplete: undefined} 4 fakeAjax(url, result => { 5 buffer.done = true 6 buffer.result = result 7 if (buffer.onComplete) buffer.onComplete(result) 8 }) 9 return buffer 10}) 11 12function waitFor(index, onAllComplete) { 13 function printAndNext(val) { 14 console.log(val) 15 if (index < urls.length - 1) { 16 waitFor(index + 1, onAllComplete) 17 } else { 18 if (onAllComplete) onAllComplete() 19 } 20 } 21 const bf = buffers[index] 22 if (bf.done) { 23 printAndNext(bf.result) 24 return 25 } 26 bf.onComplete = result => { 27 printAndNext(result) 28 } 29} 30 31waitFor(0, () => { 32 console.log("all done!") 33})

投稿2017/11/19 12:25

karamarimo

総合スコア2551

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

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

退会済みユーザー

退会済みユーザー

2017/11/19 12:44

ご回答ありがとうございます。動作確認を早く家に帰ってしたいです!
guest

0

試しに書いてみました。

(() => { const URLs = ['1.json', '2.json', '3.json', '4.json', '5.json']; const ajax = (url) => { var xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.send(''); return xhr; }; const proc = (responses) => { return () => { const flag = responses.every((response) => { return response.readyState === 4 && response.status === 200; }); if (!flag) { setTimeout(proc(responses)); } else { console.log('success'); responses.forEach((response) => { console.log(response.responseText); }); } }; }; const responses = URLs .map((url) => { return ajax(url); }); proc(responses)(); })();

投稿2017/11/20 03:34

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

CoffeeScriptで書いてみました。

CoffeeScript

1# ajaxのフェイクバージョンのつもり 2fakeAjax = (url, callback) -> 3 # レスポンスまでのランダムなタイムラグをシミュレート 4 time = Math.floor(Math.random() * (3000 - 1000) + 1000) 5 responseMock = 6 '1.txt': '1st request' 7 '2.txt': '2nd request' 8 '3.txt': '3rd request' 9 '4.txt': '4th request' 10 '5.txt': '5th request' 11 setTimeout -> 12 callback(responseMock[url]) 13 , time 14 15getFile = (url) -> 16 new Promise (resolve) -> 17 fakeAjax url, (response) -> 18 resolve(response) 19 20[ 21 getFile('1.txt') 22 getFile('2.txt') 23 getFile('3.txt') 24 getFile('4.txt') 25 getFile('5.txt') 26 Promise.resolve('all done!') 27].reduce (pre, curr) -> 28 pre.then (v) -> 29 console.log(v) 30 curr 31.then console.log

レギュレーション違反「Promiseの使用」により失格!


Promiseが禁止なら、擬きを作れば良い。

CoffeeScript

1# 約束擬き 2class PseudoPromise 3 constructor: (executor) -> 4 executor(@resolve) 5 6 then: (func) -> 7 new PseudoPromise (resolve) => 8 @fulifillment = (value) -> 9 result = func(value) 10 if result instanceof PseudoPromise 11 result.then (resultValue) -> 12 resolve(resultValue) 13 else 14 resolve(result) 15 @fulfill() 16 17 resolve: (value) => 18 @value = value 19 @fulfill() 20 21 fulfill: () -> 22 if @value? and @fulifillment? 23 @fulifillment(@value) 24 25 @resolve = (value) -> 26 new PseudoPromise (resolve) -> 27 resolve(value) 28 29# ajaxのフェイクバージョンのつもり 30fakeAjax = (url, callback) -> 31 # console.log "start: #{url}" 32 # レスポンスまでのランダムなタイムラグをシミュレート 33 time = Math.floor(Math.random() * (3000 - 1000) + 1000) 34 responseMock = 35 '1.txt': '1st request' 36 '2.txt': '2nd request' 37 '3.txt': '3rd request' 38 '4.txt': '4th request' 39 '5.txt': '5th request' 40 setTimeout -> 41 # console.log "end: #{url}" 42 callback(responseMock[url]) 43 , time 44 45getFile = (url) -> 46 new PseudoPromise (resolve) -> 47 fakeAjax url, (response) -> 48 resolve(response) 49 50[ 51 getFile('1.txt') 52 getFile('2.txt') 53 getFile('3.txt') 54 getFile('4.txt') 55 getFile('5.txt') 56 PseudoPromise.resolve('all done!') 57].reduce (pre, curr) -> 58 pre.then (v) -> 59 console.log(v) 60 curr 61.then console.log

ES5なJavaScriptでのデモ

とりあえずこのコードで動くための実装にしているため、かなり横着している部分があります(失敗する場合とか)。PromiseのPolyfillを頭に付けた方が良いと思いますが、CoffeeScriptの実装が見当たらなかったので、仕方が無く、それっぽいのを作りました。

審査委員A「これは、Promiseの使用にあたるのでは無いかね?」
審査委員B「後半のコードなど、先日の失格コードそのままでは無いか!これでは新しいコードとは言わん。」
審査委員C「それに、このPromise実装は不十分なところが多すぎる。実用的とはとても言えん。」
私「PseudoPromiseはPromiseじゃないよ、たとえPromiseだとしても、Promiseと言う名のクラスだよ!」
審査委員長「判定を言い渡す。ただのPromiseのパクリであり、創意工夫が見られないため失格とする。以上。」

(良い方法が思いついたら)PureScriptかOpalあたりで出直してきます・・・

投稿2017/11/19 12:14

編集2017/11/20 13:31
raccy

総合スコア21733

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

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

raccy

2017/11/19 12:16 編集

あ、Promise禁止って・・・すいません。私には無理です。この回答は忘れて下さい。
退会済みユーザー

退会済みユーザー

2017/11/19 12:17

お付き合い頂いてありがとうございましたm(_ _)m
raccy

2017/11/20 13:19

「手元の道具が使えないのなら、代わりの道具を作ってしまえば良い。」の精神で頑張りました。実装までに一日考え込んでしまいました。ちょっと、難しかったです。
raccy

2017/11/20 13:21

ついでに、コメントの部分を外して実行すればわかりますが、最初に全部見に良いって、終わったところまでを随時だすようになっています。順番に実行するとか、全部終わるまで待つとか、無粋なことにはなっていないはずです。
退会済みユーザー

退会済みユーザー

2017/11/20 14:09

わわわわわ。1日も考えて頂いて大変恐縮です。このお題、決して簡単なものではないですよね。皆さん、それぞれ異なるやり方をしていてすごいです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問