I currently have two promises, whereas the child is dependent on the parents success. I want to Resolve/reject the parent promise from the child promises "then".
const UserApplicaiton = require('../applications/user'), User = new UserApplicaiton();
class CheckParams {
constructor() { }
required(params, required_params) {
return new Promise(function(resolve, reject, onCancel) {
// set i
var i;
// set missed_required_params
var missed_required_params = [];
// check for userCredentials if user_id is required param, convert from credentials to user_id
if(required_params.includes("user_id")){
// set as const
const user_key = String(params.userCredentials.user_key);
const user_secret = String(params.userCredentials.user_secret);
// check in database
User.info(user_key, user_secret).then((data) => {
// if data
if(data) {
// add user_id to params
params.user_id = data[0]._id;
// loop params
for(i = 0; i < required_params.length; i++){
// if params that's required is there, else add to array
if(!(required_params[i] in params)){
missed_required_params.push(required_params[i]);
}
}
if(missed_required_params.length !== 0){
reject("Missed parameters: " + missed_required_params);
}else{
resolve(params);
}
}
}).catch((err) => {
reject(err);
});
}else{
// loop params
for(i = 0; i < required_params.length; i++){
// if params that's required is there, else add to array
if(!(required_params[i] in params)){
missed_required_params.push(required_params[i]);
}
}
if(missed_required_params.length !== 0){
console.log("hello");
return reject("Missed parameters: " + missed_required_params);
}else{
console.log("hello2");
resolve(1);
}
}
});
}
}
module.exports = CheckParams;
The goal for the second promise is to add to an object based on the response, and then resolve the parent promise, which will be used later in the code.
This doesn't work at all. Async doesn't really help.
Your problem appears to be that if(data) { is missing an else clause where you would settle the promise as well. Avoiding the Promise constructor antipattern helps to avoid such mistakes as well.
required(params, required_params) {
var promise;
if (required_params.includes("user_id")) {
const user_key = String(params.userCredentials.user_key);
const user_secret = String(params.userCredentials.user_secret);
promise = User.info(user_key, user_secret).then((data) => {
if (data) {
params.user_id = data[0]._id;
}
// else
// throw error? keep user_id undefined?
})
} else {
promise = Promise.resolve();
}
return promise.then(() => {
var missed_required_params = [];
for (var i = 0; i < required_params.length; i++) {
if (!(required_params[i] in params)) {
missed_required_params.push(required_params[i]);
}
}
if (missed_required_params.length !== 0) {
throw new Error("Missed parameters: " + missed_required_params);
} else {
return params;
}
});
}
Related
please someone help, I just cant get it.
Can you please help on how to make async/await or promise (doneCb), so script waits for first vlc_snmp(..) to finish and then to call next?
Example:
function doneCb(error) {
console.log(final_result);
final_result = [];
if (error)
console.error(error.toString());
}
function feedCb(varbinds) {
for (var i = 0; i < varbinds.length; i++) {
if (snmp.isVarbindError(varbinds[i]))
console.error(snmp.varbindError(varbinds[i]));
else {
var snmp_rez = {
oid: (varbinds[i].oid).toString()
value: (varbinds[i].value).toString()
};
final_result.push(snmp_rez);
}
}
}
var session = snmp.createSession(VLC_IP, "public", options);
var maxRepetitions = 20;
function vlc_snmp(OID) {
session.subtree(OID_, maxRepetitions, feedCb, doneCb);
}
vlc_snmp(OID_SERIAL_NUMBER);
//wait OID_SERIAL_NUMBER to finish and then call next
vlc_snmp(OID_DEVICE_NAME);
You should be able to use the async / await statements to wait for your done callback to be called. We wrap this callback in the vlc_snmp function, and return a Promise. This allows us to use the await statement.
I've mocked out some of the code that I don't have access to, it should behave somewhat similarly to the real code.
The key point here is, when a function returns a Promise we can await the result in an async function, that will give you the behaviour you wish.
final_result = [];
const VLC_IP = "";
const options = {};
const OID_ = "OID_";
const OID_SERIAL_NUMBER = "OID_SERIAL_NUMBER"
const OID_DEVICE_NAME = "OID_DEVICE_NAME"
// Mock out snmp to call feedcb and donecb
const snmp = {
createSession(...args) {
return {
subtree(oid, maxRepetitions, feedCb, doneCb) {
setTimeout(feedCb, 500, [{ oid, value: 42}])
setTimeout(doneCb, 1000);
}
}
},
isVarbindError(input) {
return false;
}
}
function doneCb(error) {
console.log("doneCb: final_result:", final_result);
final_result = [];
if (error)
console.error("doneCb: Error:", error.toString());
}
function feedCb(varbinds) {
for (var i = 0; i < varbinds.length; i++) {
if (snmp.isVarbindError(varbinds[i]))
console.error(snmp.varbindError(varbinds[i]));
else {
var snmp_rez = {
oid: (varbinds[i].oid).toString(),
value: (varbinds[i].value).toString()
};
final_result.push(snmp_rez);
}
}
}
var session = snmp.createSession(VLC_IP, "public", options);
var maxRepetitions = 20;
function vlc_snmp(OID) {
return new Promise((resolve,reject) => {
session.subtree(OID, maxRepetitions, feedCb, (error) => {
// This is a wrapper callback on doneCb
// Always call the doneCb
doneCb(error);
if (error) {
reject(error);
} else {
resolve();
}
});
});
}
async function run_vls_snmp() {
console.log("run_vls_snmp: Calling vlc_snmp(OID_SERIAL_NUMBER)...");
await vlc_snmp(OID_SERIAL_NUMBER);
console.log("run_vls_snmp: Calling vlc_snmp(OID_DEVICE_NAME)...");
//wait OID_SERIAL_NUMBER to finish and then call next
await vlc_snmp(OID_DEVICE_NAME);
}
run_vls_snmp();
I need help with code below. I get an array of items from the client then the goal is to save them in mongodb and return the list classified as 'saved' and 'failed' items. sample of failed items are those that are duplicate on a unique attribute.
I know the code below will not work because of variable scope. how do i get around it? the code below returns an empty array for both savedItems and failedItems. Thanks!
router.post('/addItems', async (req, res, next) => {
let items = req.body;
let result = {
savedItems: [],
failedItems: []
};
function saveData() {
for (i = 0; i < items.length; i++) {
item = items[i];
Model.create({ ...item }, (err, data) => {
if (err) {
result.failedItems.push(item);
} else {
result.savedItems.push(item);
}
});
}
return result;
}
saveData().then(result => {
res.send({
results: result
});
});
});
router.post('/addItems', async (req, res, next) => {
// use try catch when use async
try {
let items = req.body;
let result = {
savedItems: [],
failedItems: []
};
for (let i = 0; i < items.length; i++) {
const item = items[i];
// use the returned promise instead of callback for Model.create
const data = await Model.create({ ...item });
result.savedItems.push(item);
// if also need to handle failed item in result use anathor try catch inside
/*try {
const data = await Model.create({ ...item });
result.savedItems.push(item);
} catch( err ) {
result.failedItems.push(item);
}*/
}
res.send({
results: result
});
} catch( err ) {
// To all the errors unexpected errors + thrown rejected promises
res.send({
error: err
});
}
});
Your saveData method didn't return a promise, try this
function saveData() {
return new Promise(resolve => {
let items = req.body;
let result = {
savedItems: [],
failedItems: []
};
let promises = [];
for (i = 0; i < items.length; i++) {
item = items[i];
let promise = new Promise(resolve => {
Model.create({ ...item }, (err, data) => {
if (err) {
result.failedItems.push(item);
} else {
result.savedItems.push(item);
}
resolve();
});
});
promises.push(promise);
}
Promise.all(promises).then(() => resolve(result));
})
}
I am trying to finish my script, but for some reason i don't know, it refuses to execute in the order i put it in.
I've tried placing a 'wait' function between the JoinRequest update function and the following code, but when run, it acts as if the function call and wait function were the other way round, countering the point of the wait().
const Roblox = require('noblox.js')
var fs = require('fs');
var joinRequests = []
...
function wait(ms) {
var d = new Date();
var d2 = null;
do { d2 = new Date(); }
while(d2-d < ms*1000);
};
...
function updateJReqs() {
Roblox.getJoinRequests(4745601).then((array) => {
var i;
var final = [];
for(i = 0; i < array.length; i++) {
final.push(array[i].username);
};
if(final === '') {
final = '-None';
};
joinRequests = final
console.log('Updated join requests.')
});
}
function check() {
setTimeout(() => {
fs.readFile('Request.txt',encoding = 'utf-8', function(err, data) {
if (err) {
check();
} else {
updateJReqs(); //for some reason this function is executed alongside the below, not before it.
// Tried putting wait(x) in here.
console.log('Request received: ' + data)
var solution = joinRequests
console.log('Fuffiling request with ' + solution)
fufillRequest(solution)
fs.unlink('Request.txt', function(err) {
if(err) throw err;
});
check();
}
});
}, 400)
}
check();
The script is supposed to wait until a file is created (accomplished), update the list of join requests (accomplished) and then create a new file with the list of join requests in(not accomplished).
if I understand your code you work with async code, you need to return a promise in updateJReqs and add a condition of leaving from the function because you have an infinite recursion
function updateJReqs() {
return new Promise(resolve => {
Roblox.getJoinRequests(4745601).then((array) => {
var i;
var final = [];
for(i = 0; i < array.length; i++) {
final.push(array[i].username);
};
if(final === '') {
final = '-None';
};
joinRequests = final
console.log('Updated join requests.')
resolve();
});
}
}
async function check() {
setTimeout(() => {
fs.readFile('Request.txt',encoding = 'utf-8', function(err, data) {
if (err) {
await check();
} else {
await updateJReqs();
// Tried putting wait(x) in here.
console.log('Request received: ' + data)
var solution = joinRequests
console.log('Fuffiling request with ' + solution)
fufillRequest(solution)
fs.unlink('Request.txt', function(err) {
if(err) throw err;
});
// you dont have an exit from your function check();
return 'Success';
}
});
}, 400)
}
check().then(res => console.log(res));
Node.js database result return late inside the function
const db = req.app.db;
function getFeaturebyID(featureids) {
db.planFeatures.findOne({"_id": featureids }).then(features => {
return features.planFeaturesTitle;
});
}
const planLists ={};
db.planManagement.find({}).toArray((err, planList) => {
// res.end(JSON.stringify(planList));
featurearray = [];
var j =1;
planList.forEach(function(row) {
planLists._id = row._id;
features = row.planFeatures.split(',');
for (let i = 0; i < features.length; i++) {
featurearray[i] = getFeaturebyID(features[i]);
// console.log(getFeaturebyID(features[i]));
}
//row.planFeaturesName[j] = featurearray;
console.log(featurearray);
j++;
});
//console.log(planList);
// res.end(JSON.stringify(req.session));
res.render('stylist/plan_selection', {
top_results: planList,
title: 'Schedule',
config: req.app.config,
session: req.session,
message: common.clearSessionValue(req.session, 'message'),
messageType: common.clearSessionValue(req.session, 'messageType'),
helpers: req.handlebars.helpers,
showFooter: 'showFooter'
});
});
});
return features.planFeaturesTitle; return a value late while calling the function. I try callback but not works
This is due to asynchronous nature of node.js,
First declare your function async like this,
const getFeaturebyID = async (featureids) => {
const features = await db.planFeatures.findOne({"_id": featureids });
return features.planFeaturesTitle;
}
Then use it like this,
planList.forEach(async (row) => {
// your code here
for (let i = 0; i < features.length; i++) {
featurearray[i] = await getFeaturebyID(features[i]);
}
// your code here
});
I need to return a json object to my api. To do this I have a module that does some requests and should return the results.
My problem is grasping the promise concept and implementing it.
server.js
app.get('/users', function(req, res){
request.getUsers()
.then(function(users){
console.log(users);
res.contentType('application/json');
res.send(JSON.stringify(users));
})
.catch(function(){
console.log(users);
});
});
module.js
exports.getUsers = function(){
var params = {search_string:""};
var users = [];
return new Promise(function(resolve, reject){
var result = connection.Users.get(params, function(error,response)
{
var user = [];
for(let i = 0; i < response.data.length; i++)
{
user = response.data;
}
users.push({user});
});
if(result != null)
{
console.log(result);
resolve(result);
}
else
{
reject(new Error('Try Again'));
}
});
}
When I run the server I get the typeError: expecting a function but got [object object]
I did not really get what is wrong.
How could I return an array from my module to my API using promises?
EDIT:
app.get('/users', function(req, res){
request.getUsers()
.then(function(users){
console.log(users);
res.contentType('application/json');
res.send(JSON.stringify(users));
})
.catch(function(){
console.log("not resolved");
});
});
My problem now is actually that I am getting the .catch even before any request is made the at /users endpoint and I dont know why.
In module.js you used new Promise() constructor but the input parameter should be a function and not an object, so to fix that use:
return new Promise(function(resolve, reject) {
var result = connection.Users.get(params, function(error,response)
...
});
Notice its not new Promise({function(...) but new Promise(function(...)) ...
Read more here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Edit:
I have modified your code to work to fix the second problem:
exports.getUsers = function(){
var params = {search_string:""};
var users = [];
return new Promise(function(resolve, reject){
var result = connection.Users.get(params, function(error,response) {
if(error || !response)
{
// report error
reject(new Error('Try Again'));
}
else
{
//process response
var user = [];
for(let i = 0; i < response.data.length; i++)
{
user = response.data;
}
users.push({user});
// report success
resolve(users);
}
});
}
You need to call resolve or reject inside connection.Users.get(params, function(error,response) {
Modify your module.js code as below. You passed an object instead of a function.
register.getUsers = function () {
var params = { search_string: "" };
var users = [];
return new Promise(function (resolve, reject) {
var result = connection.Users.get(params, function (error, response) {
var user = [];
for (let i = 0; i < response.data.length; i++) {
user = response.data;
}
users.push({ user });
});
if (result != null) {
console.log(result);
resolve(result);
}
else {
reject(new Error('Try Again'));
}
});
};
you declared user variable as an array and inside the for loop isn't useful because the user variable is always equals to response.data
if response.data is array of JSON object you can push it to users array inside loop
for (let i = 0; i < response.data.length; i++) {
users.push(response.data[i]);
}
I guess you want to return the array of objects
also I recommend you to use bluebird module to return promises
and also you can use Promise.mapSeries instead of for loop like:
return Promise.mapSeries(response.data, item => {
users.push(item)
})