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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Node.js

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

AWS(Amazon Web Services)

Amazon Web Services (AWS)は、仮想空間を機軸とした、クラスター状のコンピュータ・ネットワーク・データベース・ストーレッジ・サポートツールをAWSというインフラから提供する商用サービスです。

Q&A

解決済

1回答

3259閲覧

JavaScriptで、dynamodbからデータをscan->その結果を引数に関数を使いたい

hiroga

総合スコア91

Node.js

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

AWS(Amazon Web Services)

Amazon Web Services (AWS)は、仮想空間を機軸とした、クラスター状のコンピュータ・ネットワーク・データベース・ストーレッジ・サポートツールをAWSというインフラから提供する商用サービスです。

0グッド

0クリップ

投稿2017/04/04 13:47

###前提・実現したいこと

AWSでLINEbotを作成しており、ユーザ全員にメッセージをマルチキャストしたいでうす。
dynamodbの中に入っているuseridの一覧をスキャン ->
jsonに代入してpostしたいのですが、どうしてもスキャンを待たずしてjsonのpostが始まってしまいます。

非同期処理について私なりに調べ、コードを工夫したのですがうまくいきませんでした。
どう書けば望み通りの処理ができるのか、ご教授いただけないでしょうか。

###発生している問題・エラーメッセージ

メッセージ送信とデータのスキャンが逆転してしまいます。

(前半略) 13:39:40 2017-04-04T13:39:40.345Z ea66573c-27aa-46a0-8c34-dffe44c07e69 2. Scan User and multicast message 13:39:40 2017-04-04T13:39:40.744Z ea66573c-27aa-46a0-8c34-dffe44c07e69 Start sending message...  13:39:40 2017-04-04T13:39:40.744Z ea66573c-27aa-46a0-8c34-dffe44c07e69 let send stat!  13:39:40 2017-04-04T13:39:40.746Z ea66573c-27aa-46a0-8c34-dffe44c07e69 let send End!  13:39:41 2017-04-04T13:39:41.006Z ea66573c-27aa-46a0-8c34-dffe44c07e69 onScan start  13:39:41 2017-04-04T13:39:41.006Z ea66573c-27aa-46a0-8c34-dffe44c07e69 onScan succeeded.  13:39:41 2017-04-04T13:39:41.006Z ea66573c-27aa-46a0-8c34-dffe44c07e69 This is message after Scan ->  13:39:41 2017-04-04T13:39:41.006Z ea66573c-27aa-46a0-8c34-dffe44c07e69 { to: [ 'user12345', 'user67890' ], messages: [ { type: 'text', text: 'こんにちは!' } ] }  13:39:41 END RequestId: ea66573c-27aa-46a0-8c34-dffe44c07e69

###該当のソースコード

node.js

1'use strict'; 2 3// console.log("Start code!"); 4 5const https = require('https'); 6var AWS = require("aws-sdk"); 7 8AWS.config.update({region: "us-east-1",}); 9var docClient = new AWS.DynamoDB.DocumentClient(); 10 11var message = {}; 12var params = {}; 13 14let send = (data, callback) => { 15 console.log("let send stat!"); 16 let body = JSON.stringify(data); 17 18 let req = https.request({ 19 hostname: "api.line.me", 20 port: 443, 21 path: "/v2/bot/message/multicast", 22 method: "POST", 23 headers: { 24 "Content-Type": "application/json", 25 "Content-Length": Buffer.byteLength(body), 26 "Authorization": "Bearer " + process.env.CHANNEL_ACCESS_TOKEN 27 } 28 }); 29 30 req.end(body, (err) => { 31 err && console.log(err); 32 callback(err); 33 }); 34 console.log("let send End!"); 35}; 36 37exports.handler = (event, context, callback) => { 38 console.log("Start Handler!"); 39 console.log('EVENT:', JSON.stringify(event, null, 2)); 40 41 console.log("1. Generate Message Template"); 42 43 let content = event.Records[0]; 44 console.log("content ->"); 45 console.log(content); 46 47 let sayThis = "こんにちは!"; 48 49 message = genNotification(sayThis, url); 50 console.log("This is message ->"); 51 console.log(message); 52 53 params = gen_scan_params(); 54 55 sendMessage4Scan(params, 56 () => {send(message, 57 () => {callback(); 58 }); 59 } 60 ); 61}; 62 63// sendMethodはコールバック関数なのだから、スキャン後に呼ばれることを期待していたのですが... 64function sendMessage4Scan(params,sendMethod){ 65 docClient.scan(params, onScan); 66 console.log("Start sending message..."); 67 sendMethod(); 68} 69 70function genNotification(sayThis, url){ 71 console.log("gen notify"); 72 message = { 73 "to":[], 74 "messages": [ 75 { 76 "type": "text", 77 "text": sayThis 78 } 79 ] 80 }; 81 return message; 82} 83 84function gen_scan_params(){ 85 params = { 86 TableName: process.env.TABLE_USERS, 87 ProjectionExpression: "id" 88 }; 89 return params; 90} 91 92function onScan(err, data) { 93 console.log("onScan start"); 94 if (err) { 95 console.error("Unable to scan the table. Error JSON:", JSON.stringify(err, null, 2)); 96 } else { 97 console.log("onScan succeeded."); 98 data.Items.forEach(function(user) { 99 message.to.push(user.id); 100 }); 101 console.log("This is message after Scan ->"); 102 console.log(message); 103 104 // continue scanning if we have more movies, because 105 // scan can retrieve a maximum of 1MB of data 106 if (typeof data.LastEvaluatedKey != "undefined") { 107 console.log("Scanning for more..."); 108 params.ExclusiveStartKey = data.LastEvaluatedKey; 109 docClient.scan(params, onScan); 110 } 111 } 112}

###試したこと
非同期処理について調べ、コールバック関数を利用すれば順番に処理できると知ってそう書いてみました。しかし、やり方がよくないのか処理順が変わりません。

###補足情報(言語/FW/ツール等のバージョンなど)
node.js 6.10
AWS lambda

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

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

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

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

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

guest

回答1

0

ベストアンサー

もしもdocClient.scanが非同期な処理を行うのであれば、以下の関数はdocClient.scanの結果を待たずにsendMethod()を呼びに行ってしまいます。docClient.scanの結果を待ちたい場合は、sendMethodコールバックをonScanのコールバックとして渡す必要があります。(俗に言うCallback Hellというやつですね)

js

1function sendMessage4Scan(params,sendMethod){ 2 docClient.scan(params, onScan); 3 console.log("Start sending message..."); 4 sendMethod(); 5}

上記のコードに当てはめると以下のようなイメージでしょうか。

js

1function onScan(err, data, sendMethod) { 2 // 中略 3 sendMethod(err, data); 4} 5 6function sendMessage4Scan(params, sendMethod) { 7 docClient.scan(params, (err, data) => onScan(err, data, sendMethod)); 8}

ちなみにEventEmitterを使って書き直すと見通しの良いコードになると思います。

https://nodejs.org/api/events.html

投稿2017/04/04 22:11

shuntksh

総合スコア196

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

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

hiroga

2017/04/04 22:41

なるほど!ありがとうございます。 動かすことができたので、理解の促進も兼ねて色々書き直してみます。 EventEmitterというのは初耳でした。教えていただき感謝です。書き直し時に使ってみます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問