About Promise Then - javascript

I wrote the following code to POST a mentioned message to Slack.
const resultSlack = [];
const selectedItems2 = 'XX : TESTS';
const getUserid = (value) => {
return new Promise(resolve => {
for (let i = 0; i < value.length; i++) {
let str = value[i].slice(5);
let body = {
app: XXX,
query: '"'+ str +'"'
};
kintone.api(kintone.api.url('/k/v1/records', true), 'GET', body, resp => {
resultSlack.push("<#" + resp.records[0].slackId.value + ">");
});
}
resolve(resultSlack);
});
};
getUserid(selectedItems2).then(results => {
console.log(results);
//There is an array
//0: "<#XXXXXXXX>"
//1: "<#YYYYYYYY>"
//2: "<#ZZZZZZZZ>"
//3: "<#SSSSSSSS>"
const payload = { text: results + "send already" };
//specify results in the payload, it will be ignored.
console.log(payload); // text: "send already"
});
Is it not possible to access the array passed as an argument with the then method?
How can I use the values ​​in the array in results? Please give me some advice.

Your code isn't right because it isn't properly waiting for the results from kintone.api() in your loop.
Fortunately for you, kintone.api() actually has the possiblity to return a promise! https://developer.kintone.io/hc/en-us/articles/212494388/
That means you can use async/await syntax inside your loop:
const getUserid = async (value) => {
const resultSlack = [];
for (let i = 0; i < value.length; i++) {
let str = value[i].slice(5);
let body = {
app: XXX,
query: '"'+ str +'"'
};
const resp = await kintone.api(kintone.api.url('/k/v1/records', true), 'GET', body);
resultSlack.push("<#" + resp.records[0].slackId.value + ">");
}
return resultSlack;
};
(warning: that code DOESN'T make all the looped requests simultaneously, which is possible if you feel you need it. It makes each request one at a time as written)
Now that that's written as an async function, you can do this:
getUserid(selectedItems2).then(results => ...

You have to wait for the responses to all the API calls to come in before resolving the promise.
A better way of doing this will be to transform the API calls into promises and resolve them all, here is an example:
const getUserid = (value) => {
const requests = [];
for (let i = 0; i < value.length; i++) {
let str = value[i].slice(5);
requests.push({
app: XXX,
query: '"'+ str +'"'
});
}
return Promise.all(requests.map((req) => new Promise(resolve => kintone.api(kintone.api.url('/k/v1/records', true), 'GET', req, resp => {
resolve("<#" + resp.records[0].slackId.value + ">");
})));
};

const getUserid = (value) => {
return new Promise(async resolve => {
for (let i = 0; i < value.length; i++) {
let str = value[i].slice(5);
let body = {
app: XXX,
query: '"'+ str +'"'
};
await kintone.api(kintone.api.url('/k/v1/records', true), 'GET', body, resp => {
resultSlack.push("<#" + resp.records[0].slackId.value + ">");
});
}
resolve(resultSlack);
});
};
When you calling an async function that makes a http request, you need to use await to wait until process done.

Related

Unable to fetch data from tmdb javaScript

I am trying to build a movie web using tmdb api, JavaScript, css and html only. I tried to perform search query and show the results but the problem is that the results don't show up. When debugging, the status code received is 200 but when res.json() returns it just ends the fetch function and is not moving forward to the data. I will truly appreciate your help.
Thank you.
My url
const BASE_URL = "https://api.themoviedb.org/3/";
const API_KEY = "api_key=9b62c3eb4a6bc8acd4e26602f16fa744";
let SEARCH_URL = BASE_URL + "search/movie?" + API_KEY + "&sort_by=popularity.desc&query=";
My search function:
function searchMovie() {
let f = document.getElementById('search_movie');
f.addEventListener('submit', () => {
let user_input = search_input.value;
if (user_input && user_input.trim() != '') {
let query = SEARCH_URL + user_input;
console.log();
getMovies(query);
}
});
}
My fetch function:
function getMovies(my_api) {
main.innerHTML = '';
fetch(my_api, {
method: 'GET',
cache: "no-cache",
credentials: "same-origin",
headers: { "Content-Type": "application/json" }
}).then(res => res.json()).then(data => {
let arr = data.results;
if (arr && arr.length > 0) {
arr.forEach(movie => {
addMovie(movie);
});
}
else {
getMovies(MOVIE_URL, DEFAULT_PAGE);
console.log("Can't find results");
}
}).catch(err => {
console.log(err.message);
});
}
You were mostly there. The fetch call returns a promise, so you shouldn't set innerHTML to that. Instead, use the promise to wait for the fetch to complete, then update the dom with the result.
I also suggest separating the request and the dom manipulation as I've done below. It works...
const BASE_URL = "https://api.themoviedb.org/3/";
const API_KEY = "api_key=9b62c3eb4a6bc8acd4e26602f16fa744";
let SEARCH_URL = BASE_URL + "search/movie?" + API_KEY + "&sort_by=popularity.desc&query=";
function getMovies(my_api) {
return fetch(my_api, {
method: 'GET',
cache: "no-cache",
})
.then(res => res.json())
.catch(err => {
console.log(err.message);
});
}
function renderMovies(res) {
let ul = document.getElementById('results');
ul.innerHTML = '';
res.results.forEach(result => {
let li = document.createElement('li');
li.appendChild(document.createTextNode(result.title));
ul.appendChild(li);
});
}
let f = document.getElementById('search_movie');
f.addEventListener('click', () => {
let user_input = search_input.value;
if (user_input && user_input.trim() != '') {
let query = SEARCH_URL + user_input;
getMovies(query).then(renderMovies)
}
});
<input id="search_input"></input><br/>
<button id="search_movie">SEARCH</button><br/>
<ul id="results"></ul>

Promise.all().then() gets executed before the promise.all() complete [duplicate]

This question already has answers here:
Promise.all is returning an array of undefined and resolves before being done
(3 answers)
Closed 25 days ago.
I'm trying to wrap my head around Promises, but my code doesn't work the way it should. My goal is to show that the table has loaded after all the promises are complete, but instead the code in then ("table loaded" and [undefined, undefined] 'res') get executed before. What is the way to make it work, waiting untill the table was filled?
My code
async function updateTable(accno, entity, start = null, funds) {
$table.bootstrapTable('removeAll')
prms = []
return Promise.all(
accno.map(
acc => {
let conf = {
method: 'get',
url: 'url',
params: {
account_number: acc,
start: start,
entity: entity,
}
}
axios(conf).then(function(response) {
let data = response.data
data_combined = []
for (let j = 0; j < data.return.length; j++) {
let row = data.return[j]
let temp = {
id: data.id,
// assigining more data here
}
data_combined.push(temp)
}
//another request deleted to simplify
fund_array = []
tableLoadAnimation('id-table-load', 'remove-all')
superset = [...superset, ...data_combined, ...fund_array]
$table.bootstrapTable('load', superset)
}).catch(function(error) {
console.log(error);
})
})
).then((a) => {
console.log('table loaded');
return a
}).then((res) => {
console.log(res, "res") // returns [undefined, undefined] 'res'
return res
})
}
Since axios returns promise, I had to return axios in map
async function updateTable(accno, entity, start = null, funds) {
$table.bootstrapTable('removeAll')
prms = []
prms = Promise.all(
accno.map(
acc => {
let conf = {
method: 'get',
url: 'url',
params: {
account_number: acc,
start: start,
entity: entity,
}
}
return axios(conf).then(function(response) {
let data = response.data
data_combined = []
for (let j = 0; j < data.return.length; j++) {
let row = data.return[j]
let temp = {
id: data.id,
// assigining more data here
}
data_combined.push(temp)
}
//another request deleted to simplify
fund_array = []
tableLoadAnimation('id-table-load', 'remove-all')
superset = [...superset, ...data_combined, ...fund_array]
$table.bootstrapTable('load', superset)
}).catch(function(error) {
console.log(error);
})
})
).then((a) => {
console.log('table loaded');
return a
})
}

How to make recursive promise calls?

I am working with an API that gives me data with a limit per request (here 25). Therefore, I have to recursively make promises with fetch. However, while most of my logic works, when I try to return from the function it will return an empty array. The image below will make it more clear.
const url = (conf_name) => {
return (
"https://api.elsevier.com/content/search/scopus?view=COMPLETE&cursor=*&query=CONFNAME(" +
conf_name +
")%20AND%20DOCTYPE(cp)%20AND%20SRCTYPE(p)&field=dc:creator,dc:title,dc:description,affilname,affiliation-city,affiliation-country,authkeywords,prism:doi,prism:doi,prism:coverDate"
);
};
const savePapers = (json, conf_name) => {
let temp = new Array();
for (let i = 0; i < json["search-results"]["entry"].length; i++) {
temp[i] = {
title: json["search-results"]["entry"][i]["dc:title"],
author: json["search-results"]["entry"][i]["dc:creator"],
publication_date: json["search-results"]["entry"][i]["prism:coverDate"],
doi: json["search-results"]["entry"][i]["prism:doi"],
abstract: json["search-results"]["entry"][i]["dc:description"],
author_keywords: json["search-results"]["entry"][i]["authkeywords"],
proceeding: conf_name,
};
}
return temp;
};
async function getPapers(final, url, conf_name) {
let total_amount_of_papers;
let next;
let position = 2;
try {
let response = await fetch(url, options);
let json = await response.json();
total_amount_of_papers = json["search-results"]["opensearch:totalResults"];
if (json["search-results"]["link"][position]["#ref"] == "prev")
next = json["search-results"]["link"][position + 1]["#href"];
next = json["search-results"]["link"][position]["#href"];
final = final.concat(savePapers(json, conf_name));
if (final.length === 50) {
console.log("hey",final.length);
return final;
}
await getPapers(final, next, conf_name);
} catch (error) {
console.log(error);
}
}
const createNewConf = async (conferences) => {
let final = new Array();
try {
var temp = new Conference({
acronym: conferences.acronym,
name: conferences.fullname,
area: conferences.area,
subarea: conferences.subarea,
location: conferences.location,
url: conferences.url,
description: conferences.description,
papers: await getPapers(final, url(conferences.acronym),conferences.acronym),
});
console.log(temp.papers.length);
} catch (error) {
console.log(error);
}
return temp;
};
describe("Saving records", function () {
it("Saved records to the database", async function (done) {
var conferences = [];
try {
for (var i = 0; i <= 1; i++) {
conferences[i] = await createNewConf(json_conferences[i]);
conferences[i].save().then(function () {
assert(conferences[i].isNew === True);
done();
});
}
mongoose.connection.close();
} catch (error) {
console.log(error);
}
});
});
Below you can see the length of my final array after passing the if to stop fetching more. and the second number is what I receive in the initial call
Console
Maybe anyone has an idea of the undefined behavior that occurs during return.
Your help is much appreciated.

Is there a way to wait for javascript async function to get finish before before continue

I want to wait for async function getPreprocessed to run before I return data so that message will not be undefined
data: result.rows.map(notification => {
var message
const entity_type_id = notification.entityTypeId
const preProcess = entityTypeDetails[entity_type_id].process;
async function getPreprocessed() {
let processedData = []
const promise = entityTypeDetails[entity_type_id].preProcessing
for (let index = 0; index < promise.length; index++) {
const element = promise[index];
const processed = await element.process(notification)
processedData.push(processed)
}
processedData = Object.assign({}, ...processedData.map(object => (object)))
message = res.__(entityTypeDetails[entity_type_id].messageProp,processedData)
}
getPreprocessed()
return {
message: message,
notification_notifiers: notification.notification_notifiers[0]
}
})

Node js - function to return array of objects read from sequelize database

I'm trying to create a function in node js which reads database values in and pushes them into an array, and then at the end returns this array. My functions looks like this at the moment:
function getInvoicesCount() {
let promiseInvoices = [];
let userInvCount = 0;
let deletedUserInvCount = 0;
let userInvAmount = 0;
let deletedUserInvAmount = 0;
let monthWiseInvCount = [];
db.userInvoices
.findAll({
attributes: [
'deleted_at',
[sequelize.fn('COUNT', sequelize.col('id')), 'count'],
[sequelize.fn('SUM', sequelize.col('invoice_amount')), 'amount'],
[sequelize.fn('MONTH', sequelize.col('invoice_date')), 'month']
],
group: ['invoice_date', 'deleted_at'],
paranoid: false
})
.then(result => {
result.forEach(function(element) {
userInvCount += element.dataValues.count;
userInvAmount += element.dataValues.amount;
if (element.dataValues.deleted_at != null) {
deletedUserInvAmount += element.dataValues.amount;
deletedUserInvCount += element.dataValues.count;
}
monthWiseInvCount.push(element.dataValues);
});
if (monthWiseInvCount.map(a => a === 'deleted_at')) {
monthWiseInvCount.map(a => delete a.deleted_at);
}
promiseInvoices.push(
userInvCount,
userInvAmount,
deletedUserInvCount,
deletedUserInvAmount,
monthWiseInvCount
);
});
return promiseInvoices;
}
In the main part of the code I would like to call this funtion and use a .then to get the returned array
Can you help me out how I can return a promise in the function and how will the array be accessible in the .then part?
Here are the changes you need to do to get expected result :
function getInvoicesCount() {
...
return db.userInvoices.findAll({ //<-------- 1. First add return here
...
}).then(result => {
...
return promiseInvoices; //<----------- 2. Put this line inside the then
});
// return promiseInvoices; //<----------- Remove this line from here
}
getInvoicesCount().then(data => {
console.log(data); // <------- Check the output here
})
Explanation for this :
To get .then when you can function , function should return promise ,
but in you case you are just returning a blank array ,
As per the sequlize doc , db.userInvoices.findAll returns the
promise so all you need to do is add return before the this function
, First step is done
You were return promiseInvoices; at wrong place , why ? , coz at
that you will never get the result , as the code above it run in async
manner as it is promise , so you will always get the balnk array , to
get the expected result you should return it from
db.userInvoices.findAll's then function as shown above in code
You should return the results from then to access it in the chain.
function getInvoicesCount() {
const promiseInvoices = []
let userInvCount = 0
let deletedUserInvCount = 0
let userInvAmount = 0
let deletedUserInvAmount = 0
const monthWiseInvCount = []
return db.userInvoices
.findAll({
attributes: [
'deleted_at',
[sequelize.fn('COUNT', sequelize.col('id')), 'count'],
[sequelize.fn('SUM', sequelize.col('invoice_amount')), 'amount'],
[sequelize.fn('MONTH', sequelize.col('invoice_date')), 'month'],
],
group: ['invoice_date', 'deleted_at'],
paranoid: false,
})
.then((result) => {
result.forEach((element) => {
userInvCount += element.dataValues.count
userInvAmount += element.dataValues.amount
if (element.dataValues.deleted_at != null) {
deletedUserInvAmount += element.dataValues.amount
deletedUserInvCount += element.dataValues.count
}
monthWiseInvCount.push(element.dataValues)
})
if (monthWiseInvCount.map(a => a === 'deleted_at')) {
monthWiseInvCount.map(a => delete a.deleted_at)
}
return promiseInvoices.push(
userInvCount,
userInvAmount,
deletedUserInvCount,
deletedUserInvAmount,
monthWiseInvCount,
)
})
}
You can now use
getInvoicesCount().then(() => {
//do something here
})
getData(htmlData,tags)
.then(function(data) {
console.log(data); //use data after async call finished
})
.catch(function(e) {
console.log(e);
});
function getData() {
return new Promise(function(resolve, reject) {
//call async task and pass the response
resolve(resp);
});
}
In general you can return a promise like this:
function returnPromise() {
return new Promise((resolve, reject) => {
resolve({foo: 'bar'});
});
}
So while the other answer is completely correct, you can use the above structure to create a function that returns a promise like this:
function getInvoicesCount() {
return new Promise((resolve, reject) => {
let promiseInvoices = [];
let userInvCount = 0;
let deletedUserInvCount = 0;
let userInvAmount = 0;
let deletedUserInvAmount = 0;
let monthWiseInvCount = [];
db.userInvoices
.findAll({
attributes: [
'deleted_at',
[sequelize.fn('COUNT', sequelize.col('id')), 'count'],
[sequelize.fn('SUM', sequelize.col('invoice_amount')), 'amount'],
[sequelize.fn('MONTH', sequelize.col('invoice_date')), 'month']
],
group: ['invoice_date', 'deleted_at'],
paranoid: false
})
.then(result => {
result.forEach(function(element) {
userInvCount += element.dataValues.count;
userInvAmount += element.dataValues.amount;
if (element.dataValues.deleted_at != null) {
deletedUserInvAmount += element.dataValues.amount;
deletedUserInvCount += element.dataValues.count;
}
monthWiseInvCount.push(element.dataValues);
});
if (monthWiseInvCount.map(a => a === 'deleted_at')) {
monthWiseInvCount.map(a => delete a.deleted_at);
}
promiseInvoices.push(
userInvCount,
userInvAmount,
deletedUserInvCount,
deletedUserInvAmount,
monthWiseInvCount
);
resolve(promiseInvoices); // When you are done, you resolve
})
.catch(err => reject(err)); // If you hit an error - reject
});
}
However that is a rather big function, would recommend splitting it up in smaller parts.

Categories

Resources