(Serverless Framework Module) wait for promise to resolve before return statement - ecmascript-6

Is it possible for a Serverless Framework module to wait for the "resolve" of a promise before returning?
I'm aware that promises themselves can't do that, but different frameworks/libraries (express, Jasmine, hapijs, etc.) solve this by having a method that defines when to return. I need something like this:
let http = require('http'),
Promise = require('bluebird');
let action = (done) => {
return new Promise((resolve, reject) => {
http
.get('http://domain.com', resolve.bind({}, 'all good!'))
.on('error', reject.bind({}, 'all wrong!'));
})
.then((response) => {
console.log('Result', response);
return done(response); // <----------- I wan't to see this as the response
// of the lambda function
});
};
module.exports.run = (event, context, cb) => cb(null, action(done));

No, promises don't do that. It's impossible to read from the future, and don't want to (cannot) block. Your action is still asynchronous.
But given that your export takes a callback anyway, you can simply invoke that asynchronously:
module.exports.run = (event, context, cb) => {
action().then(res => cb(null, res), err=>cb(err));
};
It would be better though of course if you just returned the promise.

Related

Javascript - Return json from fetch in an Object

I'm trying to make an application to get the recipes from https://edamam.com and I'm using fetch and Request object.
I need to make 3 request, and i thought that most beautiful way for do it is make an Object and a method that return the data in JSON.
I declarated into constructor a variable called this.dataJson, and i want to save there the data in JSON from the response. For that purpose i use this.
The problem is that i have a undefined variable.
.then( data => {this.dataJson=data;
console.log(data)} )
This is all my code.
class Recipe{
constructor(url){
this.url=url;
this.dataJson;
this.response;
}
getJson(){
var obj;
fetch(new Request(this.url,{method: 'GET'}))
.then( response => response.json())
.then( data => {this.dataJson=data;
console.log(data)} )
.catch( e => console.error( 'Something went wrong' ) );
}
getData(){
console.log("NO UNDFEIND"+this.dataJson);
}
}
const pa= new Recipe('https://api.edamam.com/search?...');
pa.getJson();
pa.getData();
I'm new studying OOP in JS and more new in Fetch requests...
If you guys can help me... Thanks very much!
Here's a solution using async-await (and a placeholder API):
class Recipe {
constructor(url) {
this.url = url;
this.dataJson;
this.response;
}
// the async keyword ensures that this function returns
// a Promise object -> we can use .then() later (1)
async getJson() {
try {
const response = await fetch(new Request(this.url, {
method: 'GET'
}))
const json = await response.json()
this.dataJson = json
} catch (e) {
console.error('Something went wrong', e)
}
}
getData() {
console.log("NO UNDFEIND:", this.dataJson);
}
}
const pa = new Recipe('https://jsonplaceholder.typicode.com/todos/1');
// 1 - here we can use the "then", as pa.getJson() returns
// a Promise object
pa.getJson()
.then(() => {
pa.getData()
});
If we want to stay closer to your code, then:
class Recipe {
constructor(url) {
this.url = url;
this.dataJson;
this.response;
}
getJson() {
// var obj; // not needed
// the "fetch" always returns a Promise object
return fetch(new Request(this.url, { // return the fetch!
method: 'GET'
}))
.then(response => response.json())
.then(data => {
this.dataJson = data;
// console.log(data) // not needed
})
.catch(e => console.error('Something went wrong'));
}
getData() {
console.log("NO UNDFEIND:", this.dataJson); // different syntax here
}
}
const pa = new Recipe('https://jsonplaceholder.typicode.com/todos/1');
// using "then", because the "fetch" returned a Promise object
pa.getJson()
.then(() => {
pa.getData();
});
The problem with your original code is that you initiate the request (pa.getJson()) and then immediately (on the next line) you want to read the data (pa.getData()). pa.getData() is called synchronously (so it happens in milliseconds), but the request is asynchronous - the data needs time to arrive (probably hundreds of milliseconds) - so, it's not there when you try to read it (it simply hasn't arrived yet).
To avoid this you have to use a technique to handle this asynchronous nature of the request:
use a callback function (blee - so last decade)
use a Promise object with then() (much better) or async-await (yeee!)
and call the pa.getData() when the response has arrived (inside the callback function, in the then() or after awaiting the result).

get real-time json data from twilio runtime with axios

I am trying to achieve real-time data from twilio server-less function. I am using a boilerplate function edited a little bit.What I want is json data in server and voice response in call consecutively .but the following code is not sending json data to server.
const axios = require('axios');
exports.handler = function (context, event, callback) {
let twiml = new Twilio.twiml.VoiceResponse();
twiml.say('you are welcome ');
const instance = axios.create({
baseURL: 'http://fafc4eac4162.ngrok.io/',
timeout: 3000,
});
instance
.post('/test', {
id: 1,
title: 'Twilio'
})
.then((response) => {
console.log(JSON.stringify(response.data));
})
.catch((error) => {
console.log(error);
return callback(error);
});
return callback(null, twiml);
};
It shows below error,but it sends data successfully if I do not use the voice response callback return callback(null, twiml) and rather use simple return callback(null, response.data);
{"message":"timeout of 3000ms exceeded","name":"Error","stack":"Error: timeout of 3000ms
exceeded\n at createError (/var/task/node_modules/axios/lib/core/createError.js:16:15)\n
at RedirectableRequest.handleRequestTimeout
(/var/task/node_modules/axios/lib/adapters/http.js:280:16)\n at Object.onceWrapper
(events.js:286:20)\n at RedirectableRequest.emit (events.js:198:13)\n at
Timeout._onTimeout (/var/task/node_modules/follow-redirects/index.js:166:13)\n at
ontimeout (timers.j...
The return callback(null, twiml); should be in the .then block.
.then((response) => {
console.log(JSON.stringify(response.data));
return callback(null, twiml);
})
Also, the error indicates the 3000ms timeout is hit, is your application returning a 200-OK?

How can I use async/await instead of a promise (.then)

I'm trying to use async/await in my project instead of .then, but it's throwing me an error
here is my code:
export const registerUser = (userData, history) => async dispatch => {
axios
.post('/api/users/register', userData)
await (res => history.push('/login'))
.catch(err => dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
and this is the error i get back
Unhandled Rejection (TypeError): (intermediate value).catch is not a function
await isn't a function that you replace then() with. It is a keyword that you put before an expression that resolves as a promise. When you use it, you also replace the catch() method with a regular try/catch.
export const registerUser = (userData, history) => async dispatch => {
try {
await axios.post('/api/users/register', userData);
history.push('/login');
} catch (err) {
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};

From ES2018 async/await to ES2015 Promises . ... timeout

I am trying to convert an ES2018 async function into an ES2015 (ES6) function, but I get a timeout, guess my ES2015 version is wrong...but where?
ES2018 version
async function connectGoogleAPI () {
// Create a new JWT client using the key file downloaded from the Google Developer Console
const client = await google.auth.getClient({
keyFile: path.join(__dirname, 'service-key.json'),
scopes: 'https://www.googleapis.com/auth/drive.readonly'
});
// Obtain a new drive client, making sure you pass along the auth client
const drive = google.drive({
version: 'v2',
auth: client
});
// Make an authorized request to list Drive files.
const res = await drive.files.list();
console.log(res.data);
return res.data;
}
ES2015 version w/Promise
function connectGoogleAPI () {
return new Promise((resolve, reject) => {
const authClient = google.auth.getClient({
keyFile: path.join(__dirname, 'service-key.json'),
scopes: 'https://www.googleapis.com/auth/drive.readonly'
});
google.drive({
version: 'v2',
auth: authClient
}), (err, response) => {
if(err) {
reject(err);
} else {
resolve(response);
}
}
});
}
You haven't translated the await of getClient. Remember, await = then (roughly). You're also falling prey to the promise creation anti-pattern: When you already have a promise (from getClient), you almost never need to use new Promise. Just use then.
Here's an example with each await converted into a then, using the chain for the subsequent operations:
function connectGoogleAPI () {
// Create a new JWT client using the key file downloaded from the Google Developer Console
return google.auth.getClient({
keyFile: path.join(__dirname, 'service-key.json'),
scopes: 'https://www.googleapis.com/auth/drive.readonly'
}).then(client => {
// Obtain a new drive client, making sure you pass along the auth client
const drive = google.drive({
version: 'v2',
auth: client
});
// Make an authorized request to list Drive files.
return drive.files.list();
}).then(res => {
console.log(res.data);
return res.data;
});
}
That last part can be just
}).then(res => res.data);
...if you remove the console.log. (Or we could abuse the comma operator.)
Notes:
Each await needs to become a then handler (there were two in the original, awaiting getClient and drive.files.list)
In a then handler, if you have to wait for another promise (such as the one from drive.files.list) you typically return it from the handler, and then use another handler to handle that result (which is why I have return drive.files.list() and then a separate handler for converting res to res.data)
Re that second point: Sometimes nesting is appropriate, such as when you need to combine the result with some intermediate value you only have with in your then handler. (For instance, if we wanted to combine res.data with client.) But generally, prefer not to nest.

javascript promise catch confusion [duplicate]

What is the best way to handle this scenario. I am in a controlled environment and I don't want to crash.
var Promise = require('bluebird');
function getPromise(){
return new Promise(function(done, reject){
setTimeout(function(){
throw new Error("AJAJAJA");
}, 500);
});
}
var p = getPromise();
p.then(function(){
console.log("Yay");
}).error(function(e){
console.log("Rejected",e);
}).catch(Error, function(e){
console.log("Error",e);
}).catch(function(e){
console.log("Unknown", e);
});
When throwing from within the setTimeout we will always get:
$ node bluebird.js
c:\blp\rplus\bbcode\scratchboard\bluebird.js:6
throw new Error("AJAJAJA");
^
Error: AJAJAJA
at null._onTimeout (c:\blp\rplus\bbcode\scratchboard\bluebird.js:6:23)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
If the throw occurs before the setTimeout then bluebirds catch will pick it up:
var Promise = require('bluebird');
function getPromise(){
return new Promise(function(done, reject){
throw new Error("Oh no!");
setTimeout(function(){
console.log("hihihihi")
}, 500);
});
}
var p = getPromise();
p.then(function(){
console.log("Yay");
}).error(function(e){
console.log("Rejected",e);
}).catch(Error, function(e){
console.log("Error",e);
}).catch(function(e){
console.log("Unknown", e);
});
Results in:
$ node bluebird.js
Error [Error: Oh no!]
Which is great - but how would one handle a rogue async callback of this nature in node or the browser.
Promises are not domains, they will not catch exceptions from asynchronous callbacks. You just can't do that.
Promises do however catch exceptions that are thrown from within a then / catch / Promise constructor callback. So use
function getPromise(){
return new Promise(function(done, reject){
setTimeout(done, 500);
}).then(function() {
console.log("hihihihi");
throw new Error("Oh no!");
});
}
(or just Promise.delay) to get the desired behaviour. Never throw in custom (non-promise) async callbacks, always reject the surrounding promise. Use try-catch if it really needs to be.
After dealing with the same scenario and needs you are describing, i've discovered zone.js , an amazing javascript library , used in multiple frameworks (Angular is one of them), that allows us to handle those scenarios in a very elegant way.
A Zone is an execution context that persists across async tasks. You can think of it as thread-local storage for JavaScript VMs
Using your example code :
import 'zone.js'
function getPromise(){
return new Promise(function(done, reject){
setTimeout(function(){
throw new Error("AJAJAJA");
}, 500);
});
}
Zone.current
.fork({
name: 'your-zone-name',
onHandleError: function(parent, current, target, error) {
// handle the error
console.log(error.message) // --> 'AJAJAJA'
// and return false to prevent it to be re-thrown
return false
}
})
.runGuarded(async () => {
await getPromise()
})
Thank #Bergi. Now i know promise does not catch error in async callback. Here is my 3 examples i have tested.
Note: After call reject, function will continue running.
Example 1: reject, then throw error in promise constructor callback
Example 2: reject, then throw error in setTimeout async callback
Example 3: reject, then return in setTimeout async callback to avoid crashing
// Caught
// only error 1 is sent
// error 2 is reached but not send reject again
new Promise((resolve, reject) => {
reject("error 1"); // Send reject
console.log("Continue"); // Print
throw new Error("error 2"); // Nothing happen
})
.then(() => {})
.catch(err => {
console.log("Error", err);
});
// Uncaught
// error due to throw new Error() in setTimeout async callback
// solution: return after reject
new Promise((resolve, reject) => {
setTimeout(() => {
reject("error 1"); // Send reject
console.log("Continue"); // Print
throw new Error("error 2"); // Did run and cause Uncaught error
}, 0);
})
.then(data => {})
.catch(err => {
console.log("Error", err);
});
// Caught
// Only error 1 is sent
// error 2 cannot be reached but can cause potential uncaught error if err = null
new Promise((resolve, reject) => {
setTimeout(() => {
const err = "error 1";
if (err) {
reject(err); // Send reject
console.log("Continue"); // Did print
return;
}
throw new Error("error 2"); // Potential Uncaught error if err = null
}, 0);
})
.then(data => {})
.catch(err => {
console.log("Error", err);
});