So... I know this is NOT the right way... but I have a box that I've got myself into which appears easiest to navigate if I can find a way to have a "get" request behave synchronously in node.js
Yes, I've tried node-sync (which looked like it should work)
Scenario is this
I know how to do the call to google translate (can easily do it for whole strings), but can't get my mind wrapped around how to get the ordering of an async callback lined up with the recursion on the parameterized string necessary for the data set I have.
This would be simple if I could make the call to the web service behave as if it were synchronous. e.g.
read string (while not EOF)
recurse (get the next token)
translate the fragment (which is done with request.get()
add translated fragment to the current string
assemble translated string
write to file
The node-sync examples worked, but I couldn't get it to work with request.get()
.
Any suggestions?
EXCERPT
// this function gets passed in a string and recursively pulls out and
// attempts to translate tokens. It needs to do this as the data source
// contains "key" = "fragment" + $(paramter1) + fragment + $(parameter2) etc
function getTokenSegment(sourceString){
s = sourceString; //lazy
// if the string contains a parameter
if (s.indexOf(leadingDelimiter) != -1) {
// extract the tokens...omitted the error checking (which all works)
translatedToken = syncTranslate(token); // <--- THIS IS WHAT I WANT...
parameter = s.substring(token.length+1, s.indexOf(trailingDelimiter)+1);
remainder = s.substring(token.length + parameter.length+1, s.length);
translatedString = translatedString + translatedToken + parameter
// recursive call to get the rest of the string
+ getTokenSegment(remainder);
}
else {
// the remainder of the string can be translated intact
translatedToken = syncTranslate(s);
translatedString = translatedString + translatedToken;
}
return (translatedString);
}
function syncTranslate(stringToTranslate) {
var sync = require('sync');
sync(function(){
var result = translate.sync(null, {key: key, q: stringToTranslate, target: language});
})
return result;
}
// translate module is from Mike Holly -- https://github.com/mikejholly/node-google-translate
// and worked perfectly when I used it on non-parameterized strings. only edit is the NULL as the
// first parameter in the callback, copied from the node-sync simple example]
var request = require('request')
, _ = require('underscore')
, querystring = require('querystring')
, util = require('util')
module.exports = function(opts, callback) {
// parse & default the arguments
opts = _.defaults(opts, {
source: 'en',
target: 'fr',
key: 'secret',
sourceText: 'text'
});
var url = 'https://www.googleapis.com/language/translate/v2?' + querystring.stringify(opts);
request.get(url, function(err, response, body){
if (err) throw err;
// parse the returned JSON
var json = JSON.parse(body);
if (json.error) {
throw json.error.message;
}
var strings = util.isArray(opts.sourceText) ? opts.sourceText : [opts.sourceText];
var result = {};
var translatedString = '';
strings.forEach(function(original, i){
result[original] = json.data.translations[i].translatedText;
translatedString = result[original];
});
callback(null, translatedString);
});
};
I am guessing here, because your question is not clear enough. I appreciate your difficulties because it's hard to talk about software. I think you forgot to wrap your code in a Sync block:
// Run in a fiber
Sync(function(){
// your code
})
Source: https://github.com/0ctave/node-sync#examples
I give you a hint. Try the most simple task first. Try to translate only one word, then use the translated word. Do this thing with request.get()
within Sync
. When this works, you trust the software more and are more confident to continue with more complicated things.
A very popular module for writing sync code in node.js is async. For your problem I would try the waterfall
function:
async.waterfall([
// your first function
function(callback){
callback(null, 'one', 'two');
},
// your second function
function(arg1, arg2, callback){
callback(null, 'three');
},
// your third function
function(arg1, callback){
// arg1 now equals 'three'
callback(null, 'done');
}
], function (err, result) {
// result now equals 'done'
});