I am using AWS lambda function with NodeJS for my alexa skill. But I am stuck in using async function.
Here is the requirement
On launching, a asynchronous function function1 is called
After the completion of function1, the result is passed to async function2.
The result of function2 should be spoken out to user
So I am trying to solve this by using Promise chaining. Below is my pseudocode
function function1() {
return new Promise((resolve, reject) => {
//some async operation
if (result1) {
resolve(result1);
} else {
reject(error);
}
});
}
function function2(result1) {
return new Promise((resolve, reject) => {
//some async operation
if (result2) {
resolve(result2);
} else {
reject(error);
}
});
}
const mainHandler = {
'LaunchRequest': function () {
function1()
.then(result1 => function2(result1))
.then(result2 => {
//succcess
this.response.cardRenderer(result2);
this.response.speak(result2);
this.response.listen(config.HELP_REPROMPT);
this.emit(':responseReady');
}).catch(err => {
//error
this.response.cardRenderer(err);
this.response.speak(err);
this.response.listen(config.HELP_REPROMPT);
this.emit(':responseReady');
});
},
};
Now the issue I am facing is that alexa terminates prematurely after first function execution without waiting for function2 to be executed. Not sure what I am doing wrong here. Any help would be appreciated. Thanks in advance.
Note: If there is only one async function then it works fine. i.e below code works fine.
const mainHandler = {
'LaunchRequest': function () {
function1()
.then(result1 => {
//succcess
this.response.cardRenderer(result1);
this.response.speak(result1);
this.response.listen(config.HELP_REPROMPT);
this.emit(':responseReady');
})
.catch(err => {
//error
this.response.cardRenderer(err);
this.response.speak(err);
this.response.listen(config.HELP_REPROMPT);
this.emit(':responseReady');
});
},
};'
Issue is when 2 async functions are involved
See if this helps:
function function1() {
return new Promise((resolve, reject) => {
//some async operation
if (result1) {
resolve(result1);
} else {
reject(error);
}
});
}
function function2(result1) {
return new Promise((resolve, reject) => {
//some async operation
if (result2) {
resolve(result2);
} else {
reject(error);
}
});
}
const ErrorHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'LaunchRequest';
},
async handle(handlerInput, error) {
result1 = await function1();
result2 = await function2(result1);
/* rest of code according to version2 */
},
};
For v1 and v2 sdk difference click here.
Related
When using a simple callback such as in the example below:
test() {
api.on( 'someEvent', function( response ) {
return response;
});
}
How can the function be changed to use async / await? Specifically, assuming 'someEvent' is guaranteed to be called once and only once, I'd like the function test to be an async function which does not return until the callback is executed such as:
async test() {
return await api.on( 'someEvent' );
}
async/await is not magic. An async function is a function that can unwrap Promises for you, so you'll need api.on() to return a Promise for that to work. Something like this:
function apiOn(event) {
return new Promise(resolve => {
api.on(event, response => resolve(response));
});
}
Then
async function test() {
return await apiOn( 'someEvent' ); // await is actually optional here
// you'd return a Promise either way.
}
But that's a lie too, because async functions also return Promises themselves, so you aren't going to actually get the value out of test(), but rather, a Promise for a value, which you can use like so:
async function whatever() {
// snip
const response = await test();
// use response here
// snip
}
It's annoying that there isn't a straightforward solution, and wrapping return new Promise(...) is fugly, but I have found an ok work-around using util.promisify (actually it also kinda does the same wrapping, just looks nicer).
function voidFunction(someArgs, callback) {
api.onActionwhichTakesTime(someMoreArgs, (response_we_need) => {
callback(null, response_we_need);
});
}
The above function does not return anything, yet. We can make it return a Promise of the response passed in callback by doing:
const util = require('util');
const asyncFunction = util.promisify(voidFunction);
Now we can actually await the callback.
async function test() {
return await asyncFunction(args);
}
Some rules when using util.promisify
The callback must be the last argument of the function that is gonna be promisify
The supposed-callback must be in the form (err, res) => {...}
Funny thing is we do not need to ever specifically write what's the callback actually is.
async/await is magic. You can create a function asPromise to handle this kind of situations:
function asPromise(context, callbackFunction, ...args) {
return new Promise((resolve, reject) => {
args.push((err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
if (context) {
callbackFunction.call(context, ...args);
} else {
callbackFunction(...args);
}
});
}
and then use it when you want:
async test() {
return await this.asPromise(this, api.on, 'someEvent');
}
the number of args is variable.
You can achieve this without callbacks , use promise async await instead of callbacks here how I would do this. And also here I have illustrated two methods to handle errors
clickMe = async (value) => {
// begin to wait till the message gets here;
let {message, error} = await getMessage(value);
// if error is not null
if(error)
return console.log('error occured ' + error);
return console.log('message ' + message);
}
getMessage = (value) => {
//returning a promise
return new Promise((resolve, reject) => {
setTimeout(() => {
// if passed value is 1 then it is a success
if(value == 1){
resolve({message: "**success**", error: null});
}else if (value == 2){
resolve({message: null, error: "**error**"});
}
}, 1000);
});
}
clickWithTryCatch = async (value) => {
try{
//since promise reject in getMessage2
let message = await getMessage2(value);
console.log('message is ' + message);
}catch(e){
//catching rejects from the promise
console.log('error captured ' + e);
}
}
getMessage2 = (value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(value == 1)
resolve('**success**');
else if(value == 2)
reject('**error**');
}, 1000);
});
}
<input type='button' value='click to trigger for a value' onclick='clickMe(1)' />
<br/>
<input type='button' value='click to trigger an error' onclick='clickMe(2)' />
<br/>
<input type='button' value='handling errors with try catch' onclick='clickWithTryCatch(1)'/>
<br/>
<input type='button' value='handling errors with try catch' onclick='clickWithTryCatch(2)'/>
const getprice = async () => {
return await new Promise((resolve, reject) => {
binance.prices('NEOUSDT', (error, ticker) => {
if (error) {
reject(error)
} else {
resolve(ticker);
}
});
})}
router.get('/binanceapi/price', async function (req, res, next) {
res.send(await binanceAPI.getprice());});
First, I know this is a common question. I'm trying to get a handle on how to use async / await in place of setTimeouts, but all the examples I see online use a setTimeout to simulate the async. This throws me off when it's a set timeout that I'm trying to replace.
In the function below, I want this.filteredResultsto await the results of an API call before trying to filter those results and assign it to this.filteredResults.
getResults() {
let allResults= airtableQuery.getTable("Transfers"); // API call using imported 'getTable' function
console.log(allResults); // returns full array ▶[] although it's not available for filtering yet.
setTimeout(() => { // I want to replace this timeout
this.filteredResults = allResults.filter(
(result) => result.fields.User === "dev"
);
}, 250); // random ms that is roughly how long airtableQuery takes for the API call.
},
And the airtableQuery:
getTable(table) {
let recordsArr = [];
base(`${table}`)
.select({
maxRecords: 8000,
})
.eachPage(
function page(records, fetchNextPage) {
records.forEach((record) => {
recordsArr.push(record);
});
fetchNextPage();
},
function done(err) {
if (err) {
this.$toasted.error(err);
}
}
);
return recordsArr;
},
Please make the outer function an async function and then await the results before filtering them.
async function getResults() {
let allResults = await airtableQuery.getTable("Transfers");
this.filteredResults = allResults.filter(
(result) => result.fields.User === "dev"
);
},
Given that getTable() is not a Promise, await will not do anything. For that reason, we can make getTable() return a Promise which will resolve with recordsArr.
getTable(table) {
return new Promise((resolve, reject) => {
let recordsArr = [];
base(`${table}`)
.select({
maxRecords: 8000,
})
.eachPage(
function page(records, fetchNextPage) {
records.forEach((record) => {
recordsArr.push(record);
});
fetchNextPage();
},
function done(err) {
if (err) {
this.$toasted.error(err);
reject(err)
}else {
resolve(recordsArr)
}
}
);
})
}
Hope it helps.
i always likes primise,this my code show you
getTable(table) {
return new Promise((res, rej) => {
let recordsArr = [];
base(`${table}`)
.select({
maxRecords: 8000,
})
.eachPage(
function page(records, fetchNextPage) {
records.forEach((record) => {
recordsArr.push(record);
});
fetchNextPage();
res(recordsArr)
},
function done(err) {
if (err) {
this.$toasted.error(err);
rej(err)
}
}
);
})
}
getResults() {
airtableQuery.getTable("Transfers").then(res => {
let allResults = res
console.log(allResults);
this.filteredResults = allResults.filter(
(result) => result.fields.User === "dev"
);
});
}
Here's the code
console.log("Before");
const p = getUser(1);
p.then(user => {
console.log(user);
getRepositories(user.github);
}).then(repos => {
console.log(repos);
});
console.log("after");
function getUser(id) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log("Calling a database " + id);
resolve({ id: id, github: "Zain" });
}, 2000);
});
}
function getRepositories(username) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log(`Calling Api for ${username}`);
resolve(["repo1", "repo2", "repo3"]);
}, 2000);
});
}
I'm having trouble with consuming the promise returned by getRepositories() function. Above is my implementation but it doesn't work and returns undefined (instead of the array [repo1, repo2, repo3]).
Here's the output:
I want the array to return after logging "Calling Api for Zain" but the undefined is shown before it, but I don't know why, so I need help regarding this.
You need a return statement in your first .then:
p.then(user => {
console.log(user);
return getRepositories(user.github);
}).then(repos => {
console.log(repos);
});
There’s a special syntax to work with promises in a more comfortable fashion, called “async/await”. It’s surprisingly easy to understand and use.
async function init() {
console.log("Before");
const user = await getUser(1);
console.log(user);
const repos = await getRepositories(user.github);
console.log(repos);
console.log("after");
}
init();
async function getUser(id) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log("Calling a database " + id);
resolve({ id: id, github: "Zain" });
}, 2000);
});
}
async function getRepositories(username) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log(`Calling Api for ${username}`);
resolve(["repo1", "repo2", "repo3"]);
}, 2000);
});
}
For more information: https://javascript.info/async-await
I have 3 functions which I need to run in order and one needs to finish before the other runs so I've done this:
var fs = require('fs');
async function create() {
fs.writeFile('newfile.txt', 'some text here', (err) => {
if (err) throw err;
console.log('File is created successfully.');
return ('File is created successfully.');
});
}
async function waitt() {
setTimeout(() => { return 'waited!' }, 10000);
}
async function read() {
fs.readFile('newfile.txt', {encoding: 'utf-8'}, (err,data) => {
if (!err) {
console.log('received data: ' + data);
return ('received data: ' + data);
} else {
console.log(err);
}
});
}
async function process() {
let [r1, r2, r3] = await Promise.all([create(), waitt(), read()]);
console.log(r1 + ' ' + r2 + ' ' + r3);
}
process();
So, process() runs create() which creates a file, then run waitt() which just pauses and finally read() shows the contents of the file.
The issue I'm having is that it's running in this order:
create()
read()
and then waitt()
instead of
create()
waitt()
read()
which is what I want.
How can I fix this?
This won't work:
async function waitt() {
setTimeout(() => { return 'waited!' }, 10000);
}
Because, you're return-ing from within the setTimeout callback, not the async-marked wait function.
To mix callback-style code and async/await you must first convert callback style code to use Promises, or use fs-extra which already provides fs functions returning promises.
Something like this:
function waitt() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('waited...')
}, 10000)
})
}
The same applies to the rest of your functions.
Also note that if a function explicitly returns a Promise, it doesn't need to be marked as async to be awaited, since await essentially works with Promises.
Now for the order:
Promise.all doesn't guarantee order, for that you might be able to get away with a simple for..of, or just call the functions yourself.
function wait() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('waited...')
resolve('foo')
}, 500)
})
}
// Assume this is your promisified read function.
function read() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('read...')
resolve('bar')
}, 500)
})
}
// Assume this is your promisified create function.
function create() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('created...')
resolve('baz')
}, 500)
})
}
;(async () => {
try {
await create()
await wait()
await read()
} catch (err) {
console.error(err)
}
})()
Your problem is that Promise.all does not guarantee the order of processing, just that all the promises in the list are processed.
Can you not just say:
await create();
await read();
await waitt();
For example, look at this code:
function myPromise() {
return new Promise(resolve => {
setTimeout(() => {
resolve('Stack Overflow');
}, 2000);
});
}
async function sayHello() {
const externalFetchedText = await myPromise();
console.log('Hello ' + externalFetchedText);
}
sayHello();
What's the right way for showing a (.gif image file) loading before the request and hide this after Promise is resolved and the process is finished?
Most of time promises are abstracted into seprated module and are independent. So you should never do any other operation than async operation in the promises. You can show your gif while resolving the promises. See below code to show animation after you make async call, and hide it after resolution. You also have to handle reject scenario via try/catch/finally block.
function myPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Stack Overflow');
// reject('Some Error')
}, 2000);
});
}
function showSpinner() {
document.getElementById('loader').style.display = 'block';
}
function hideSpinner() {
document.getElementById('loader').style.display = 'none';
}
async function sayHello() {
try {
showSpinner()
const externalFetchedText = await myPromise();
console.log('Hello ' + externalFetchedText);
} catch (err) {
console.error(err);
} finally {
hideSpinner()
}
}
sayHello();
<img id="loader" style="display:none" src="http://chimplyimage.appspot.com/images/samples/classic-spinner/animatedCircle.gif" />
You can do it in the promise if you want all the calling code that uses this promise to display the loading animation.
function myPromise() {
return new Promise(resolve => {
// Show image
setTimeout(() => {
// Hide image
resolve('Stack Overflow');
}, 2000);
});
}
async function sayHello() {
const externalFetchedText = await myPromise();
console.log('Hello ' + externalFetchedText);
}
sayHello();
function myPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
//resolve('Stack Overflow');
reject('hello world');
}, 2000);
});
}
const newPromise = myPromise().then(result => {
"hide here"
return result;
}).catch(error => {
"hide here"
return error
});
async function sayHello() {
const externalFetchedText = await newPromise;
console.log('Hello ' + externalFetchedText);
}
sayHello();