Undefined reading in promise chain - javascript

I have a simple employee profile generator app. Everything works just as expected up until the promise for generatePage(employeeData). The console correctly logs employeeData but it is not getting passed to generatePage. Does anyone have insight into why? I have also included a picture of the beginning code for generate-page.js and the "undefined" console error message.
const {writeFile, copyFile} = require('./utils/generate-site.js');
const generatePage = require('./src/page-template.js');
const mockData = [
{
// lots of mock data objects here
},
]
let employeeData = mockData;
function init() {
return inquirer.prompt(questions.startQuestions);
}
function getEmployeeData(answers) {
if (answers.role === 'Engineer') {
let engineer = new Engineer (
answers.name,
answers.id,
answers.email,
answers.role
)
return getEngineerData(engineer);
} else if (answers.role === 'Intern') {
let intern = new Intern (
answers.name,
answers.id,
answers.email,
answers.role
)
return getInternData(intern)
} else if (answers.role === 'Manager') {
let manager = new Manager (
answers.name,
answers.id,
answers.email,
answers.role
)
return getManagerData(manager)
}
}
function getEngineerData(engineer) {
return new Promise((resolve) => {
resolve (
inquirer.prompt(questions.engineerQuestions)
.then ((response) => {
engineer = {...engineer, ...response};
// console.log(engineer)
employeeData.push(engineer)
}
)
)
})
}
function getInternData(intern) {
return new Promise((resolve) => {
// same as getEngineerData function
})
}
function getManagerData(manager) {
return new Promise((resolve) => {
// same as getEngineerData function
})
}
function confirm() {
return inquirer.prompt(questions.confirmQuestion)
}
function buildTeam() {
init()
.then(answers => getEmployeeData(answers))
.then(confirm)
.then(response => response.confirmAdd ? buildTeam() : console.log(employeeData))
.then(employeeData => generatePage(employeeData))
.then(pageHTML => {
return writeFile(pageHTML)
})
.then (writeFileResponse => {
console.log(writeFileResponse);
return copyFile()
})
.then(copyFileResponse => {
console.log(copyFileResponse);
})
.catch (err => {
console.log(err);
});
}
buildTeam();

console.log returns "undefined" so the solution was to return the employeeData array in the promise chain to pass on.
.then(response => {
if (response.confirmAdd) {
buildTeam()
return employeeData
} else {
return employeeData
}
})

Related

cancel multiple promises inside a promise on unmount?

hi i want to cancel promise on unmount since i received warning,
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
My code:
const makeCancelable = (promise: Promise<void>) => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then(
(val) => (hasCanceled_ ? reject({ isCanceled: true }) : resolve(val)),
(error) => (hasCanceled_ ? reject({ isCanceled: true }) : reject(error))
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
useEffect(() => {
const initialize = async () => {
const getImageFilesystemKey = (remoteUri: string) => {
const [_, fileName] = remoteUri.split('toolbox-talks/');
return `${cacheDirectory}${fileName}`;
};
const filesystemUri = getImageFilesystemKey(uri);
try {
// Use the cached image if it exists
const metadata = await getInfoAsync(filesystemUri);
if (metadata.exists) {
console.log('resolve 1');
setFileUri(filesystemUri);
} else {
const imageObject = await downloadAsync(uri, filesystemUri);
console.log('resolve 2');
setFileUri(imageObject.uri);
}
// otherwise download to cache
} catch (err) {
console.log('error 3');
setFileUri(uri);
}
};
const cancelable = makeCancelable(initialize());
cancelable.promise
.then(() => {
console.log('reslved');
})
.catch((e) => {
console.log('e ', e);
});
return () => {
cancelable.cancel();
};
}, []);
but i still get warning on fast press, help me please?
You're cancelling the promise, but you are not cancelling the axios call or any of the logic that happens after it inside initialize(). So while it is true that the console won't print resolved, setFileUri will be called regardless, which causes your problem.
A solution could look like this (untested):
const makeCancelable = (promise: Promise<void>) => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then(
val => (hasCanceled_ ? reject({ isCanceled: true }) : resolve(val)),
error => (hasCanceled_ ? reject({ isCanceled: true }) : reject(error))
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
}
};
};
const initialize = async () => {
const getImageFilesystemKey = (remoteUri: string) => {
const [_, fileName] = remoteUri.split("toolbox-talks/");
return `${cacheDirectory}${fileName}`;
};
const filesystemUri = getImageFilesystemKey(uri);
try {
// Use the cached image if it exists
const metadata = await getInfoAsync(filesystemUri);
if (metadata.exists) {
console.log("resolve 1");
return filesystemUri;
} else {
const imageObject = await downloadAsync(uri, filesystemUri);
console.log("resolve 2");
return imageObject.uri;
}
// otherwise download to cache
} catch (err) {
console.error("error 3", err);
return uri;
}
};
useEffect(() => {
const cancelable = makeCancelable(initialize());
cancelable.promise.then(
fileURI => {
console.log("resolved");
setFileUri(fileURI);
},
() => {
// Your logic is such that it's only possible to get here if the promise is cancelled
console.log("cancelled");
}
);
return () => {
cancelable.cancel();
};
}, []);
This ensures that you will only call setFileUri if the promise is not cancelled (I did not check the logic of makeCancelable).

TypeError: Cannot read property 'then' of undefined. Getting this error when I am trying to run updatefirst function

I am trying to run the updatefirst function but getting the same error again and again even when I pass a predefined value to the resolve function in get_plo_amount.The console.log(result) line runs which shows than there was no issue in fetching the data. I don't know what I am doing wrong here :( .Any help will be appreciated. Thanks .
const get_plo_amount = function(p){
plo.findOne({phone : p}).then((result) => {
console.log(result) //this line is running
return new Promise((resolve,reject) => {
resolve(result.daily_amount)
})
}).catch((e) => {
console.log("catch")
return new Promise((resolve,reject) => {
reject(e)
})
})
}
//updatefirst
const updatefirst = function(plo,date){
driver.find({associated_plo : plo}).then((result) => {
//console.log(result)//delete this
get_plo_amount(plo).then((amount) => {
console.log(amount)
var arr
for(i=0;i<result.length;i++){
var pdue = parseInt(result[i].balance) + amount
var d_obj = {
driver : result[i].name,
phone : result[i].phone,
auto_number : result[i].auto_number,
amount : pdue,
}
// console.log(d_obj)//delete this
arr[i] = d_obj
}
const obj = {
associated_plo : plo,
date : date,
earning : "0",
payments : arr
}
const t = new transactions(obj)
t.save().then(() => {
return "success"
}).catch((e) => {
return e
})
}).catch((e) => {
console.log(e)
return e
})
}).catch((e) => {
console.log(e)
return e
})
}
You should return a promise, to make the then() method work.
Try updating your function like this:
const get_plo_amount = function(p){
return plo.findOne({phone : p}).then((result) => {
console.log(result) //this line is running
return new Promise((resolve,reject) => {
resolve(result.daily_amount)
})
}).catch((e) => {
console.log("catch")
return new Promise((resolve,reject) => {
reject(e)
})
})
}
2 more changes
you can return result.daily_amount without creating another promise
the promise in the catch is rejecting so you might as well remove the catch
const get_plo_amount = function(p){
return plo.findOne({phone : p}).then((result) => {
console.log(result) //this line is running
result.daily_amount;
});
}

How to use promise return TypeError - javascript

I wrote a Promise function to turn Object of Object to Array of Object:
function objectToArray(objectOfObject) {
return new Promise((resolve,reject) => {
var newArray = Object.keys(objectOfObject).map(key => {
let object = objectOfObject[key]
object['id'] = key
return object;
})
resolve(newArray)
reject('error')
})
}
So my Resolve will return an Array of object, but how can I return TypeError by using the reject in case of the objectOfObject is not an Object of Object, which will caused typeerror I believe?
Thanks.
you can use if...else
function objectToArray (objectOfObject) {
return new Promise((resolve, reject) => {
if (typeof objectOfObject === 'object') {
var newArray = Object.keys(objectOfObject).map(key => {
let object = objectOfObject[key]
object['id'] = key
return object
})
resolve(newArray)
} else {
reject(new TypeError())
}
})
}
or use try... catch
function objectToArray (objectOfObject) {
return new Promise((resolve, reject) => {
try {
var newArray = Object.keys(objectOfObject).map(key => {
let object = objectOfObject[key]
object['id'] = key
return object
})
resolve(newArray)
} catch (error) {
reject(error)
}
})
}
I suppose you might want to make the error an instance of Error:
reject(new Error('error'))
function objectToArray (objectOfObject) {
return new Promise((resolve, reject) => {
if (typeof objectOfObject !== 'object') {
reject(new TypeError())
}
var newArray = Object.keys(objectOfObject).map(key => {
let object = objectOfObject[key]
object['id'] = key
return object
})
resolve(newArray)
})
}

How return a value after a forEach loop using Promises?

I need to know how to return a value after a forEach loop using Promises. In this moment, when I launch my main, I get :
[ Promise { <pending> }, Promise { <pending> } ]
(my sampleidlist contains only 2 records)
This is my code :
MongoClient.connect("mongodb://127.0.0.1/myproject", function(err, db) {
return db.collection('RUN').find({
"idRun": query.idRun
}).toArray()
.then((out) => {
var sampleidlist = out[0].SAMPLE_ID
var pazlist = []
// Promisearr is the array of promises where I try to push the promises
var Promisearr = []
// there is the function find_paz that return idPaz for every sampleId in sampleidlist
function find_paz(sampleid) {
// I return a new Promise for every sampleId
// I want to create an array of idPaz
return new Promise((resolve, reject) => {
db.collection('PATIENTS').find({
"SAMPLE_ID": sampleid
}).toArray()
.then((pazArr) => {
var singlepaz = []
singlepaz.push(pazArr[0].idPaz)
return singlepaz
})
.then((singlepaz) => {
pazlist.push(singlepaz)
})
})
}
// Here the forEach loop
sampleidlist.forEach(sampleid => {
Promisearr.push(
find_paz(sampleid)
)
})
Promise.resolve(Promisearr)
.then(Promise.all(Promisearr))
.then(value => {
// value return {promise<pending>}
// I want that value is the array of idPaz
console.log(value)
}).catch((err) => {
console.log('errored', err);
})
}).catch((err) => {
console.log('errored', err);
})
})
Any suggest?
Thank you very much :)
You have it mixed up between Promise.all and Promise.resolve. Here:
return db.collection('RUN').find({
"idRun": query.idRun
}).toArray()
.then((out) => {
var sampleidlist = out[0].SAMPLE_ID
var pazlist = []
var Promisearr = []
function find_paz(sampleid) {
return db.collection('PATIENTS').find({
"SAMPLE_ID": sampleid
}).toArray()
.then((pazArr) => {
var singlepaz = []
singlepaz.push(pazArr[0].idPaz)
return singlepaz
})
.then((singlepaz) => {
pazlist.push(singlepaz)
return;
})
})
}
Promise.all(sampleidlist.map(find_paz))
.then(values => {
//values is an array with all the promises resolved
//pazlist should have your data.
}).catch((err) => {
console.log('errored', err);
})
}).catch((err) => {
console.log('errored', err);
})
Give it a try, let me know if you need clarification or if it doesn't work.
You are using Promise.resolve() and Promise.all() the wrong way. You should just call Promise.all() then .then(), like this :
Promise.all(Promisearr).then(value =>
console.log(value)
)

How to make the following code wait for and api call to be ready before resuming?

The following code loops through a formFields array. There are two types of fields: those with files to upload and those that don't. I'm keeping count of the "queued" fields and the "finished" ones, so I know when to update the form
const payload = {}
const fields = {
queued: [],
finished: []
}
formFields.forEach(field => {
fields.queued.push(field)
if (hasUploadFiles(field)) { // FOR FILE INPUTS
utils.mapCallPromise(field.value, file => {
api.uploadPhoto(file, field).then(uploadedPhoto => {
payload[field.name] = uploadedPhoto
fields.finished.push(field)
})
})
} else { // FOR NORMAL INPUTS
payload[field.name] = field.value
fields.finished.push(field)
}
})
if (fields.queued.length === fields.finished.length) {
console.log('use the payload to update the form')
}
The problem is api.uploadPhoto is triggering after if (fields.queued.length === fields.finished.length).
How to modify the code so if (fields.queued.length === fields.finished.length) triggers after api.uploadPhoto is done?
UPDATE:
This is api.uploadPhoto and utils.mapCallPromise:
api.uploadPhoto = async (file = {}, field = {}) => {
if (utils.includes(api.usServers, api.env)) {
return await usImageUpload.toFirebase(file, field)
} else {
return await cnImageUpload.toQCloud(file, field.userId, field.sizes)
}
}
utils.mapCallPromise = (object, callback) => {
return new Promise((resolve, reject) => {
return Array.prototype.slice.call(object).map(value => {
return resolve(callback(value))
})
})
},
Using Promise.all and array map method, you could do the following
Promise.all(formFields.map(field => {
if (hasUploadFiles(field)) { // FOR FILE INPUTS
return api.uploadPhoto(file, field).then(uploadedPhoto => {
return {field, uploadedPhoto};
});
} else { // FOR NORMAL INPUTS
return {field};
}
})).then(results => {
//results is an array of objects that are either {field, uploadedPhoto} or just {field}
});

Categories

Resources