Return values from SetTimeout function ( Promise.Then()) - javascript

In the code below , Values are RETURNED correctly from a queued Promise.then() chain .
CODE:
let cond_1 = true;
let data = 'Data Received....';
let err = 'Error';
var p1 = new Promise(function(resolve,reject){
if(cond_1){
resolve(data);
}else{
reject(err); }})
p1.then((data)=>{console.log(data);return 'Wait....';})
.then((val1)=>{console.log(val1); return 'Finished';})
.then((val2)=>{console.log(val2)})
.catch((err)=>{console.log(err)});
Output :
Data Received....
Wait....
Finished
However, the same RETURNED values from a chained SetTimeout function are returned 'UNDEFINED'.
CODE:
p1.then((data)=>{console.log(data); return 'Wait.....'; })
.then((val1)=>{setTimeout(function(val1){console.log(val1); return 'Finished';},1000)})
.then((val2)=>{setTimeout(function(val2){console.log(val2);},1000)})
.catch((err)=>{console.log(err)});
Output:
Data Received....
undefined
undefined
How to resolve this?

Try taking advantage of Lexicographic nature of Javascript.
Instead of making a function v1,v2 which your functions takes within setTimeout, just use an arrow function. In this way you are using the v1,v2 returned from promise.
Do this
let cond_1 = true;
let data = 'Data Received....';
let err = 'Error';
var p1 = new Promise(function(resolve, reject) {
if (cond_1) {
resolve(data);
} else {
reject(err);
}
})
p1.then((data) => {
console.log(data);
return 'Wait.....';
})
.then((val1) => {
setTimeout(() => {
console.log(val1);
}, 1000);
return 'Finished';
})
.then((val2) => {
return setTimeout(() => {
console.log(val2)
}, 1000)
})
.catch((err) => {
console.log(err)
});
What you did was you created a new variable v1,v2 for your function. You can only use that when you pass value v1,v2 in that function. That function won't use v1,v2 returned from promise as you expect.

Related

how to get return value of promise

Here is a function to find mx records of a service and i need to save the one value(with the lowest priority) to make a request to it. How can I save and return this value?
const dns = require('dns');
const email = '...#gmail.com'
let res = email.split('#').pop();
function getMxRecords(domain) {
return new Promise(function(resolve, reject) {
dns.resolveMx(domain, function(err, addresses) {
if (err) {
//console.log(err, err.stack)
resolve(null);
} else {
//console.log(addresses);
let copy = [...addresses];
//console.log(copy);
let theone = copy.reduce((previous, current) => {
if (previous.priority < current.priority) {
return current;
}
return previous;
});
resolve(theone);
}
});
});
}
let a = getMxRecords(res);
console.log(a);
Yeah, so i need to export this module to make a request to it like below;
let socket = net.createConnection(25, request(email), () => {})
so for this my function should request me or array or object with only one value, when i'm trying it doesn't work, i always get this:
Promise { } //HERE IS RETURN FROM MY FUNCTION (WITH .THEN)
Error in socket connect ECONNREFUSED 127.0.0.1:25
A Promise is mostly an asynchronous call. It returns an Promise-Object that will resolve or reject the Promise. To access the result, you will call some functions:
function getMxRecords(domain) {
return new Promise(function(resolve, reject) {
dns.resolveMx(domain, function(err, addresses) {
if (err) {
//console.log(err, err.stack)
resolve(null);
} else {
//console.log(addresses);
let copy = [...addresses];
//console.log(copy);
let theone = copy.reduce((previous, current) => {
if (previous.priority < current.priority) {
return current;
}
return previous;
});
resolve(theone);
}
});
});
}
getMxRecords(res)
.then(yourResolveValueProvided => {
// Your code if the promise succeeded
})
.catch(error => {
// Your code if the promises reject() were called. error would be the provided parameter.
})

Making a function chainable with then()

I have a function that uses fetch() to get a value from a database, which is then used to update an element on my page:
function AjaxUpdate(_element, _url, _form_data) {
if (!_element) return; // Nothing to update.
if (concurrency++ == 0)
LoadStatus(_form_data === undefined ? "Loading..." : "Processing...");
fetch(_url, {
method: _form_data === undefined ? "GET" : "POST",
body: _form_data,
})
.then((response) => response.text())
.then((text) => {
if (_element.nodeName == "INPUT") _element.value = text;
else _element.innerHTML = text;
/* inserted */ return new Promise(function (resolve, reject) {
resolve(text);
});
})
.catch((error) => alert(error.message))
.finally(() => {
if (--concurrency == 0) LoadStatus("");
});
}
I like this function to be chainable, by calling it like this:
const company_form = document.getElementById("company_form");
const company_properties = document.getElementById("company_properties");
const cmc_info = document.getElementById("cmc_info");
AjaxUpdate(company_properties, "company?action=edit&CompanyID=12345", new FormData(company_form))
.then(text => { AjaxUpdate(cmc_info, "company?action=editcmc&CompanyID=12345"); });
The initial call is a POST (updates the database) and the second call should wait for the first to complete before starting. To do so I inserted a return new Promise() statement, but that does not work as expected. The initial function call is executed (database is updated) but then I get an error message "TypeError: function AjaxUpdate(...) is undefined".
The single call version is used many times and runs OK; when I put a then() at the end, it breaks down.
Could anyone give me a push...?
You need to add a return statement to AjaxUpdate for the case where you fetch data. And for consistency, you should return a promise in the if (!_element) case too.
function AjaxUpdate(_element, _url, _form_data) {
if (!_element) return Promise.resolve();
// ^^^^^^^^^^^^^^^^^---- MODIFIED
if (concurrency++ == 0)
LoadStatus(_form_data === undefined ? "Loading..." : "Processing...");
return fetch(_url, {
//^^^^^^---- ADDED
method: _form_data === undefined ? "GET" : "POST",
body: _form_data,
})
.then((response) => response.text())
.then((text) => {
if (_element.nodeName == "INPUT") _element.value = text;
else _element.innerHTML = text;
return text;
})
.catch((error) => alert(error.message))
.finally(() => {
if (--concurrency == 0) LoadStatus("");
});
}
Your return statement is scoped under the callback of the then invocation. So AjaxUpdate is not actually returning that Promise but an implicit undefined.
I suggest you three possible solutions.
Return the fetch promise chain result
function AjaxUpdate(_element, _url, _form_data) {
if (!_element) {
// return a dummy Promise
return Promise.resolve(/* whatever you want as a default*/);
}
// ...
// Returning fetch promise chain
return fetch(...)
.then(...)
.then((text) => {
// ...
return text;
// text will be passed from the next `then` invocation
});
}
Return a whole Promise which resolves whenever you need to
function AjaxUpdate(_element, _url, _form_data) {
return new Promise((resolve, reject) => {
if (!_element) {
resolve(/* Any default value ...*/);
// or even reject();
}
// ...
fetch(...)
.then(...)
.then((text) => {
// ...
resolve(text);
})
.catch(reject)
.finally(...);
});
}
Make AjaxUpdate async so it will return an implicit Promise
async function AjaxUpdate(_element, _url, _form_data) {
if (!_element) {
return;
}
// ...
try {
const response = await fetch(...);
const text = await response.text();
// ...
return text;
} catch (e) {
// ...
}
// Finally
// ...
}
Hope it helps.

How to alter result of callback/promise function?

I have a function that can return result in both callback and promise:
function foo(args, cb) {
// do stuff
const promise = getSomePromise();
if (cb) {
promise.then((result) => {
cb(null, result);
}, (err) => {
cb(err);
});
} else {
return promise;
}
}
I want to alter the result of promise before returning it. How to do this in a way that introduces the least amount of spaghetti code?
Add a function to alter and return modified result
function alterResult(result){
const alteredResult = /// do something to result
return alteredResult;
}
Then add it in a then()to:
const promise = getSomePromise().then(alterResult);
You can write a function which returns something and pass it to the callback when initiating it like this
function foo(cb) {
const promise = getSomePromise(); // return some promise
promise.then((result) => { // result is here just "Hello"
cb(doSomething(result)); // return the altered value here to the callback
})
}
function getSomePromise() {
return new Promise((resolve, _) => resolve("Hello")) // make a new promise
}
function doSomething(res) { // define a function that alters your result
return res + ", World"
}
foo((val) => console.log(val)) // log it

Callback function is not executed within returned Promise

I have two functions that return promise. The first one provide host value, and the second one use the host value to get IP address. I can see that the first function is running without any issue. But looks like the callback function side getHostIps is not executed at all. Not sure why it happens....what's wrong with my promise function?
my promise chain:
getHostedZoneId(dns)
.then(hostZoneId => {
getHostIps(dns, hostZoneId);
})
.then(hostIps => {
logger.Info(hostIps); //hostIps is undefined
})
.catch(err => logger.error(err));
getHostedZoneId:
var getHostedZoneId = function(dns) {
var params = {
DNSName: dns,
};
return new Promise((resolve, reject) => {
findHostZoneByDNS(params, function(err, data) {
if(err) {
reject(err);
}
else {
resolve(data);
}
});
});
}
getHostIps:
var getHostIps = function(dns, hostZoneId) {
var params = {
HostedZoneId: hostZoneId,
StartRecordName: dns,
};
return new Promise((resolve, reject) => {
findHostIps(params, function(err, data) {
//logger.info("get there");
if(err) {
reject(err);
}
else {
resolve(data);
}
});
});
}
I logged hostIps and err and data, all of them are defined. So I am sure that the callback function inside promise is not executed. But not sure how to fix it.
Any feedback is appreciated! Thanks!
You have to return the promise from your then statement to complete the chain.
getHostedZoneId(dns)
.then(hostZoneId => {
return getHostIps(dns, hostZoneId); // Add return
})
.then(hostIps => {
logger.Info(hostIps);
})
.catch(err => logger.error(err));

How can I call series of Promise functions?

The requirement is finishing the current function before moving to the next call:
var current_data = something;
Run(current_data).then((data1) => {
Run(data1).then(data2 => {
Run(data2).then(data3 => {
// and so on
})
})
});
The example above is only possible if I know exactly how much data I want to get.
In order to make the nested promises part of promise chain, you need to return the nested promises.
Run(current_data).then((data1) => {
return Run(data1).then(data2 => {
return Run(data2).then .....
});
});
I'm gonna assume your data is paginated and you don't know how many pages there are, therefore you can use a while loop with await inside of an async function like so:
(async function() {
var currentData = someInitialData;
// loop will break after you've processed all the data
while (currentData.hasMoreData()) {
// get next bunch of data & set it as current
currentData = await Run(currentData);
// do some processing here or whatever
}
})();
You can use the async-await to make code more readable.
async function getData(current_data){
let data1 = await Run(current_data)
let data2 = await Run(data1);
let result = await Run(data2);
return result;
}
Calling the getData function
getData(data)
.then(response => console.log(response))
.catch(error => console.log(error));
Try to avoid nested promises. If you need to call a series of promises, which depend on the previous call's response, then you should instead chain then like the following following -
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 1000);
});
promise1.then((response) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(response + ' b');
}, 1000);
});
}).then((responseB) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(responseB + ' c');
}, 1000);
});
}).then((responseC) => {
console.log(responseC); // 'foo b c'
})
if your code can support async-await then what Mohammed Ashfaq suggested is an alternative.
If you are executing the same function over and over again but on different data, I would make a recursive function that returns return a Promise.
I just look at my example below using an an array of numbers, you can edit it to your current case.
var current_data = [1,2,4,5,6]
function Run(data){
if(data.length === 0)
return Promise.resolve(data);
return new Promise((resolve, reject)=>{
//your async operation
//wait one second before resolving
setTimeout(()=>{
data.pop()
console.log(data)
resolve(data)
},1000)
})
.then((results)=>{
return Run(results)
})
}
Run(current_data)

Categories

Resources