I used promises, callbacks and external API for the firt time but I'm not sure that's the best way to use them.
My program traslates words from a langage to another using a langae Pivot and systran.io API.
the function Translate will translate word and send response via a callback.
then in the POST request I used promises to chain tasks.
var express = require('express');
var request = require('request');
var router = express.Router();
router.post("/", function(req, res) {
console.log
var resultat
var promise = new Promise((resolve, reject) => {
translate(req.query.source, "en", req.query.content, function(resa) {
resolve(resa);
})
}).then(function(resolve) {
console.log(resolve);
translate("en", req.query.target, resolve, function(resa2) {
console.log(resa2);
})
});
});
function translate(source, target, content, callback) {
let result;
result = request("https://api-platform.systran.net/translation/text/translate?input=" + content + "&source=" + source + "&target=" + target + "&key=xxxxxxxx-783f-4f90-aea4-7fb357016647", function(err, data, body) {
body = JSON.parse(body);
console.log(body);
callback(body.outputs[0].output)
})
}
module.exports = router;
Is there a best way to write my program which is already working ?
Related
I think the rendering takes place before the searching of the string on the files, i have tried different methods but don't seems to get this working. any help will be appreciated. im a noob on to the nodejs. im trying to get the id of the user and query and get all the data and there after see if he is in any of the lists given and finally render the page.
const j = [];
let name = '';
const filename = [];
var ext = '';
module.exports = function(app, express) {
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.post('/cusdetails', isLoggedIn, function (req, res) {
var cusid=req.body.cusid;
var insertQuerys = "SELECT * FROM customer WHERE cusid=? ORDER BY rowid DESC LIMIT 1";
connection.query(insertQuerys,[cusid],
function(err, rows){
rows.forEach( (row) => {
name=row.fncus;
});
fs.readdir('./views/iplist', function(err, files) {
if (err)
throw err;
for (var index in files) {
j.push(files[index])
}
j.forEach(function(value) {
var k = require('path').resolve(__dirname, '../views/iplist/',value);
fs.exists(k, function(fileok){
if(fileok) {
fs.readFile(k, function(err, content) {
if (err) throw err;
if (content.indexOf(name) > -1) {
ext = path.extname(k);
filename.push(path.basename(k, ext));
}
});
}
else {
console.log(" FileNotExist ");
}
});
});
});
console.log(filename);
res.render('cusdetails.ejs', {rows: rows, user:req.user , aml: filename });
});
})
You can create simple Promise wrapper and then use it inside async/await function to pause execution until resolved.
// use mysql2 package as it provides promise, less work to write promise wrappers
const mysql = require('mysql2/promise');
// create the connection to database
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
database: 'test'
});
// sample wrapper
function some(k) {
// more advisable to have local variables, why do you need this to be array?
var filename = [];
return new Promise((resolve, reject) => {
// doing this is also not recommended check nodejs documentation **fs.exists** for more info
fs.exists(k, function(fileok){
if(fileok) {
fs.readFile(k, function(err, content) {
if (err) reject(err);
if (content.indexOf(name) > -1) {
ext = path.extname(k);
filename.push(path.basename(k, ext));
resolve(filename)
}
});
}
else {
// reject(new Error("FileNotExist"))
console.log(" FileNotExist ");
}
});
})
}
// note the use of async
app.post('/cusdetails', isLoggedIn, async function (req, res) {
var cusid=req.body.cusid;
var insertQuerys = "SELECT * FROM customer WHERE cusid=? ORDER BY rowid DESC LIMIT 1";
// using await to pause excution, waits till query is finished
const [rows] = await connection.query(insertQuerys,[cusid])
rows.forEach( (row) => {
name=row.fncus;
});
// then you can
var result = await some(k)
...
Note however this way you loose the advantage of concurrent execution, as it's kindoff blocking. If the result of one call is not used in another, you can execute in parallel and await for result to achieve sequencing like
const [rows] = connection.query(insertQuerys,[cusid])
var result = some(k)
console.log(await rows) // do something
console.log(await result) // do something
JavaScript is asynchronous. This means that if you have a function with a callback (i.e. your query), the callback will be called asynchronously, at an unknown time, while the other code executes.
You need to look up some tutorials how to deal with callbacks, to get a proper understanding of it. Another method is using async/await and/or promises.
Basically, if you take the following code:
console.log("this will print first");
setTimeout(function () {
console.log("this will print last");
}, 1000);
console.log("this will print second");
If you run the code above, the top level is executed synchronously, so, it first calls console.log, then it executes setTimeout, which is synchronous. It sets a timeout, then says "I'm ready", and the code continues to the other console.log. After 1 second (1000 milliseconds), the callback in the setTimeout function is executed, and only then that console.log is called. You can not make the rest of the code wait this way, you need to restructure your code or read into promises.
Problem Statement:
Consider a node js program running with express library for REST communication.
There are multiple REST API calls and all the API's are using a single blocking resource which can run only one request at a time like serial port.
I have a situation that I receive multiple parallel requests to the API calls which inturn use the serial port for some purpose.
How do I channelize the API calls from different methods and then streamline it and then execute it one by one and then return back the response to the corresponding request ?
Code Snippet:
/**
* This function is a blocking function that utilizes the serial port
*/
function request_response(shield, channel, parameter, parameterValue) {
var promise = new Promise(function (resolve, reject) {
var commandString = modbusRTURequestGenerator.modbusRTURequestGenerator(shield, channel, parameter, data, parameterValue);
serialOUT(commandString).then(() => {
Promise.race([serialIN(), timeOut()]).then(results => {
resolve(results);
});
});
});
return promise;
}
/**
* This is a GET Request API to get the parameter values.
*/
router.get("/getParameter", function (req, res) {
var shield = req.query.shield;
var channel = req.query.channel;
var parameter = req.query.parameter;
request_response(shield, channel, parameter, undefined).then(
(result) => {
res.send(result);
});
});
/**
* This is a POST Request API to set the parameter values.
*/
router.post("/setParameter", function (req, res) {
var shield = req.query.shield;
var channel = req.query.channel;
var parameter = req.query.parameter;
var parameterValue = req.body.value;
request_response(shield, channel, parameter, parameterValue).then(
(result) => {
res.send(result);
});
});
/**
* This is a GET Request API for Scan functionality.
*/
router.get("/scan", function (req, res) {
var msg = {};
var cmds_arr = [];
for (var i = 1; i <= constants.NUMBER_OF_SHIELDS; i++) {
cmds_arr.push(i + "," + constants.SCAN_COMMAND_REGISTER);
}
asyncLoop(cmds_arr, function (item, next) {
var params = item.split(",");
var shield = params[0];
var register = params[1];
request_response(shield, undefined, register, undefined).then(
(result) => {
msg[data] = result;
next();
}
});
}, function () {
res.send(msg);
});
});
There are 3 kinds of HTTP REST API's: scan, getParameter and setParameter. All these 3 are accessing the request_response function. So, when I run the scan API and then trigger the getParameter API parallely, I am getting false results.
I am building an API using ExpressJS, NodeJS
The issue is when I call my API using Postman, I do not get any returned results. I do not know how to make Postman wait for the function to return the allproduct result. I am using callback but it is just not working, I have tried many simple callback codes in my Services part of the code but none of them work. Only Async Await makes the Postman API stop and wait for result, however i am using a third party API called Pipedrive, which works only with callback. If i can somehow make the Pipedrive API work with Async/Await it might solve my issue
Route:
var express = require('express')
var router = express.Router()
// Push the job to different controller functions
var PipedriveController = require('../../controllers/pipedrive.controller');
router.get('/products', PipedriveController.pipedriveAllProducts)
// Export the router
module.exports = router;
Controller
var PipedriveService = require('../services/pipedrive.service')
// Async Controller Function
exports.pipedriveAllProducts = async function(req, res, next){
// let family = req.param.options;
try {
let all_products = await PipedriveService.pipedriveAllProducts()
// Return All product liist with Appropriate HTTP header response
return res.status(200).json({status: 200, all_products});
} catch(e){
// Return an Error Response Message
return res.status(400).json({status: 400, message: e.message});
}
}
Service:
var Pipedrive = require('pipedrive');
var pipedrive = new Pipedrive.Client('SECRET', { strictMode: true });
// Saving the context of this module inside the _the variable
_this = this
exports.pipedriveAllProducts = async function operation(options){
// Array of product object - after which will be converted to JSON
const allproducts = [];
function iterateprods (err, products) {
if (err) throw err;
for (var i = 0; i < products.length; i++) {
// console.log(products[i].prices["0"].price);
let product = {
"id": products[i].code,
"name": products[i].name,
"price": products[i].prices["0"].price
}
allproducts.push(product)
}
console.log(JSON.stringify(allproducts));
return allproducts
}
pipedrive.Products.getAll({},iterateprods)
}
First, no need tu put async before the operation function, you need to wrap your service in a promise, you can do something like this :
var Pipedrive = require('pipedrive');
var pipedrive = new Pipedrive.Client('SECRET', { strictMode: true });
// Saving the context of this module inside the _the variable
_this = this
exports.pipedriveAllProducts = function operation(options){
// Array of product object - after which will be converted to JSON
const allproducts = [];
return new Promise((resolve, reject) => {
pipedrive.Products.getAll({}, function(err, products){
if (err) reject(err);
for (var i = 0; i < products.length; i++) {
// console.log(products[i].prices["0"].price);
let product = {
"id": products[i].code,
"name": products[i].name,
"price": products[i].prices["0"].price
}
allproducts.push(product)
}
console.log(JSON.stringify(allproducts));
resolve(allproducts);
});
}
I have an android game that has 40,000 users online. And each user send request to server every 5 second.
I write this code for test request:
const express = require('express')
const app = express()
const pg = require('pg')
const conString = 'postgres://postgres:123456#localhost/dbtest'
app.get('/', function (req, res, next) {
pg.connect(conString, function (err, client, done) {
if (err) {
return next(err)
}
client.query('SELECT name, age FROM users limit 1;', [], function (err, result) {
done()
if (err) {
return next(err)
}
res.json(result.rows)
})
})
})
app.listen(3000)
Demo
And for test this code with 40,000 requests I write this ajax code:
for (var i = 0; i < 40000; i++) {
var j = 1;
$.ajax({
url: "http://85.185.161.139:3001/",
success: function(reponse) {
var d = new Date();
console.log(j++, d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds());
}
});
}
SERVER detail(I know this is poor)
Questions:
this code (node js)only response 200 requests per second!
how can improve my code for increase number response per second?
this way(ajax) for simulate 40,000 online users is correct or not?
if i use socket is better or not?
You should use Divide&Conquer algorithm for solving such problems. Find the most resource inefficient operation and try to replace or reduce an amount of calls to it.
The main problem that I see here is that server open new connection to database on each request which possibly takes most of the time and resources.
I suggest to open connection when the server boots up and reuse it in requests.
const express = require('express')
const app = express()
const pg = require('pg')
const conString = 'postgres://postgres:123456#localhost/dbtest'
const pgClient
pg.connect(conString, function (err, client, done) {
if (err) {
throw err
}
pgClient = client
})
app.get('/', function (req, res, next) {
pgClient.query('SELECT name, age FROM users limit 1;', [], function (err, result) {
if (err) {
return next(err)
}
res.json(result.rows)
})
})
app.listen(3000)
For proper stress load testing better use specialized utilities such as ab from Apache. Finally, sockets are better for rapid, small data transfer but remember it has problems with scaling and in most cases became very inefficient at 10K+ simultaneous connections.
EDIT: As #robertklep pointed out, better use client pooling in this case, and retrieve client from pool.
I am working with a NodeJS project where i need to update a table and afterwards restart a service. Unfortunately the service restarts before the table has been updated. So i assume this is a normal async behaviour.
How do i synchronize this?
var sqlite3 = require('sqlite3').verbose();
var express = require('express');
var app = express();
var router = express.Router();
var db = new sqlite3.Database('/home/test/testApp.db', 'OPEN_READWRITE');
router.route('/')
.get(function(req, res) {
res.render('index', { data: dbConfigRow });
})
.post(function(req, res) {
// console.log(req.body);
db.serialize(function() {
for (var key in req.body) {
db.run("UPDATE config SET " + key + "='" + req.body[key] + "'");
}
exec('systemctl restart demoApp');
});
res.json(200);
});
You should check out Async or any one of the popular promise libraries (When.js, Q.js, Bluebird).
Any of these should solve your problem. In Async it might look something like this using series:
.post(function(req, res) {
async.series([
function(callback){
db.serialize(function() {
for (var key in req.body) {
db.run("UPDATE config SET " + key + "='" + req.body[key] + "'");
}
callback()
})
},
function(callback){
exec('systemctl restart demoApp'); //Assuming this is synchronous
callback()
}
],
function(error, results){ //Using the optional callback
res.send(200);
}
);
});
This assumes db.run is synchronous (it looks like it is).
All this said, it looks like your current implementation was returning 200 before it finished all the db/restarting tasks. You might try moving the response after the exec. That may also work. Let me know if this solves your issue.