I try use the tapable in brower, but i got a error
VM994:11 Uncaught TypeError: _callback is not a function
at eval (eval at create (HookCodeFactory.js:33:10), :11:1)
at ***
error
My code is an follows:
import { AsyncParallelHook } from "tapable";
const asyncParallelHook = new AsyncParallelHook();
asyncParallelHook.tapAsync('listener', (next: any) => {
console.log('listener--start');
setTimeout(() => {
console.log(next)
next(null, 'listener')
}, 2000);
})
asyncParallelHook.callAsync('demo', (err, result) => {
console.log('Execute successfully', err, result)
})
The same code is possible in node!
Related
I have a route handler in express.js and inside it, I am calling an asynchronous function which should return me some value. I am using bluebird promises to handle the promises. Below is a sample code.
router.js
---------
router.post('/endpoint', (req, res) => {
return Promise.try(() => serviceFile.validate())
.then(() => {
console.log('Response: ', response);
})
.catch((error) => {
console.log('Error: ', error) // TypeError: expecting a function but got [object Promise]
})
})
serviceFile.js
--------------
async function validate() {
return Promise.try(() => axios.post('/endpoint'))
.then((response) => response.data)
.catch((error) => {
console.log('Error: ', error.response.data) // successfully printing the error data object
throw error;
})
}
When I call the validate() in the Service.js file, it fails the request (which I want) and successfully prints the error. But I don't want to handle the error here, so I re-throw it and expects to handle it in the router.js file. But in the router.js file, I am getting error as undefined and it says, TypeError: expecting a function but got [object Promise]
I am not getting any clue where I am doing wrong. Any help would be greatly appreciated.
its sort of unclear what serviceFile.validate does unless thats the second function you listed, this might be a more clear way of using promises
router.post('/endpoint', async (req, res) => {
try {
const response = await serviceFile.validate()
console.log('Response: ', response);
} catch (err) {
console.log('Error: ', error)
}
})
function validate () {
return new Promise(async (resolve, reject) => {
try {
const res = await axios.post('/endpoint')
resolve(res.data)
} catch (err) {
if (err.response && err.response.data) {
reject(err.response.data)
} else {
reject(err)
}
}
})
}
I have this code that invokes a function and has a callback with error and data parameters:
app.get('/lights', (req,res) => {
hue.getLights(function(err, data){
if(err) res.status(401).send("An error occured: ", err.message);
res.send(data);
});
})
The function that it invokes is:
let getLights = function(callback){
fetch(`http://${gateway}/api/${username}/lights`, {
method: 'GET'
}).then((res) => {
if(res.ok){
return res.json();
}else{
throw new Error(res.message);
}
}).then((json) => {
lightsArray = []
for (var i in json){
lightsArray.push(`ID: ${i} Name: ${json[i]['name']}`);
}
return callback(lightsArray);
});
}
When I make an error occur, the error isn't caught, nor is any error displayed, the app crashes with the message: UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch().
Now I know I'm missing a lot, this is my first time using callbacks, let alone handling errors.
Could someone help me with making the error callback work, also show me some flaws in what I'm doing, as I know this won't catch every error that may happen, only errors caused by using the fetch function.
Thanks!
This is my other function (similar but uses a catch aswell, which I think I have done incorrectly too):
let getLightDetails = function (ID, callback) {
fetch(`http://${gateway}/api/${username}/lights/${ID}`, {
method: 'GET'
}).then((res) => {
if(res.ok){
return res.json();
}else{
throw new Error(res.message);
}
}).then((json) => {
return callback(json);
})
.catch((err) => {
console.log(err);
return callback(err.message);
});
}
Mixing callbacks and promises can make your code a bit messy. I would stick to promises:
app.get('/lights', (req, res) => {
return hue.getLights()
.then(data => {
res.send(data);
})
.catch(err => {
res.status(401).send("An error occured: ", err.message);
});
})
and hue.js
const fetch = require('node-fetch');
const gateway = "192.168.0.12";
const username = "username-A";
function fetchAPI(url, ...rest) {
return fetch(`http://${gateway}/api/${username}${url}`, ...rest);
}
function getLights() {
return fetchAPI(`/lights`)
.then(res => res.json())
.then(json => json.map((light, i) => `ID: ${i} Name: ${light.name}`));
}
function getLightDetails(id) {
return fetchAPI(`/lights/${id}`)
.then(res => res.json());
}
function getLightState(id) {
return fetchAPI(`/lights/${id}`)
.then(res => res.json())
.then(light => `Name: ${light.name} On: ${light.state.on}`);
}
function setLightState(id, state) {
return fetchAPI(`/lights/${id}/state`, {
method: 'PUT',
body: JSON.stringify({"on": state })
}).then(res => res.json());
}
module.exports = { getLights, getLightDetails, getLightState, setLightState };
material that i used
Firebase (cloud-firestore)
Javascript
windows 10
What did I do ?
I tried to access from local but it didn't work.
This is an error in the console
functions: ReferenceError: err is not defined
at exports.createScreams.functions.https.onRequest (C:\Users\taiga\Github\React2\Full-stack-app\socialape-functions\functions\index.js:59:19)
at runFunction (C:\Users\taiga\AppData\Roaming\npm\node_modules\firebase-tools\lib\emulator\functionsEmulatorRuntime.js:570:20)
at C:\Users\taiga\AppData\Roaming\npm\node_modules\firebase-tools\lib\emulator\functionsEmulatorRuntime.js:545:19
at Generator.next (<anonymous>)
at C:\Users\taiga\AppData\Roaming\npm\node_modules\firebase-tools\lib\emulator\functionsEmulatorRuntime.js:8:71
at new Promise (<anonymous>)
at __awaiter (C:\Users\taiga\AppData\Roaming\npm\node_modules\firebase-tools\lib\emulator\functionsEmulatorRuntime.js:4:12)
at runFunction (C:\Users\taiga\AppData\Roaming\npm\node_modules\firebase-tools\lib\emulator\functionsEmulatorRuntime.js:542:12)
at C:\Users\taiga\AppData\Roaming\npm\node_modules\firebase-tools\lib\emulator\functionsEmulatorRuntime.js:569:15
at Generator.next (<anonymous>) ! Your function was killed because it raised an unhandled error.
index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp({ credential: admin.credential.applicationDefault() });
const firestore = admin.firestore();
firestore.settings({ignoreUndefinedProperties:true});
exports.helloWorld = functions.https.onRequest((request, response) => {
response.send("Hello world");
});
exports.getScreams = functions.https.onRequest((req, res) => {
admin.firestore().collection('screams').get()
.then(data => {
let screams
data.docs.forEach(doc => {
screams.push(doc.data());
});
return res.json(screams);
})
.catch((err) => console.error(err));
});
exports.createScreams = functions.https.onRequest((req, res) => {
// if(req.method !== 'post') {
// return res.status(400).json({ error: 'method not allowed '})
// }
const newScreams = {
body: req.body,
userHandle: req.userHandle,
createdAt: admin.firestore.Timestamp.fromDate(new Date())
};
admin
.firestore()
.collection('screams')
.add(newScreams)
.then(doc => {
res.json({Message: `document ${doc.id} created successfully`});
})
.catch((err) => {
res.status(500).json({ error: 'something went wrong'});
});
console.error(err);
});
Does someone know this error?
Instead of using err outside the catch callback:
.catch((err) => {
res.status(500).json({ error: 'something went wrong'});
});
console.error(err);
You probably meant to put it inside the callback where err is defined:
.catch((err) => {
console.error(err);
res.status(500).json({ error: 'something went wrong'});
});
I have tried to fix the nesting problems but nothing I have used works, not even Google Cloud Functions - warning Avoid nesting promises promise/no-nesting.
How can I restructure this method? Below is the code.
exports.payout = functions.https.onRequest((request, response) => {
var uid = "nYIAHSYimJMHbMkXqDt9PQ0U3Nf2";
getPayoutsPending(uid).then((array) => {
getPayoutsAmount(array).then((value) => { **// avoid nesting promises**
var valueTrunc = parseFloat(Math.round(value * 100) / 100).toFixed(2);
const sender_batch_id = Math.random().toString(36).substring(9);
const sync_mode = 'false';
const payReq = JSON.stringify({
sender_batch_header: {
sender_batch_id: sender_batch_id,
email_subject: "You have a payment"
},
items: [
{
recipient_type: "EMAIL",
amount: {
value: valueTrunc,
currency: "CAD"
},
receiver: "me#gmail.com",
note: "Thank you.",
sender_item_id: "Payment"
}
]
});
paypal.payout.create(payReq, sync_mode, (error, payout) => {
if (error) {
console.warn(error.response);
response.status('500').end();
throw error;
} else {
console.info("payout created");
console.info(payout);
**// avoid nesting problems**
updatePaymentsPending(uid, sender_batch_id).then(() => {
response.status('200').end();
return;
}).catch((error) => {
return console.error(error);
})
}
});
return null;
}).catch((error) => {
return console.error(error);
})
return null;
}).catch((error) => {
return console.error(error);
})
});
The lines marked // avoid nesting promises are the problems.
EDIT - Result from Answer
line 111:20 reads:
return paypal.payout.create(payReq, sync_mode, (error, payout) => {
line 120:21 reads:
}).then(() => {
EDIT #2
After changing the code to what #imjared provided, i am getting the following errors:
ReferenceError: sender_batch_id is not defined
at exports.payout.functions.https.onRequest (/user_code/index.js:136:40)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:57:9)
at /var/tmp/worker/worker.js:689:7
at /var/tmp/worker/worker.js:673:9
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
then:
Function execution took 1327 ms, finished with status: 'crash'
then:
ReferenceError: paymentRequest is not defined
at Promise (/user_code/index.js:111:17)
at buildPaymentRequest (/user_code/index.js:90:14)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
EDIT #3 - response from destenson post
Code I have:
exports.payout = functions.https.onRequest((request, response) => {
return getPayoutsPending(request.body.uid)
.then(array => getPayoutsAmount(array))
.then(value => {
var valueTrunc = parseFloat(Math.round(value * 100) / 100).toFixed(2);
const sender_batch_id = Math.random().toString(36).substring(9);
const sync_mode = 'false';
const payReq = JSON.stringify({
sender_batch_header: {
sender_batch_id: sender_batch_id,
email_subject: "You have a payment"
},
items: [
{
recipient_type: "EMAIL",
amount: {
value: valueTrunc,
currency: "CAD"
},
receiver: request.body.email,
note: "Thank you.",
sender_item_id: "Payment"
}
]
});
return paypal.payout.create(payReq, sync_mode, (error, payout) => {
if (error) {
console.warn(error.response);
response.status('500').end();
throw error;
}
console.info("payout created");
console.info(payout);
return updatePaymentsPending(request.body.uid, sender_batch_id)
}).then(() => {
response.status('200').end();
return null;
});
})
.catch(error => {
console.error(error);
});
});
When app is executed, the functions logs show this:
TypeError: Cannot read property 'then' of undefined
at getPayoutsPending.then.then.value (/user_code/index.js:120:15)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
then:
{ batch_header:
{ payout_batch_id: '*************',
batch_status: 'PENDING',
sender_batch_header:
{ sender_batch_id: '************',
email_subject: 'You have a payment' } },
links:
[ { href: 'https://api.sandbox.paypal.com/v1/payments/payouts/*******',
rel: 'self',
method: 'GET',
encType: 'application/json' } ],
httpStatusCode: 201 }
then:
uncaught exception
then:
ReferenceError: uid is not defined
at paypal.payout.create (/user_code/index.js:119:46)
at IncomingMessage.<anonymous> (/user_code/node_modules/paypal-rest-sdk/lib/client.js:140:13)
at emitNone (events.js:91:20)
at IncomingMessage.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:974:12)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)
lastly:
Function execution took 1517 ms, finished with status: 'crash'
EDIT #4 - final result
After executing application, the following log from function is:
I would solve this problem by chaining the promises, instead of nesting them. When you return a value from a then() callback, it becomes a new promise that can be then be used again.
I have not tested this modified version of your code, but I hope you get the gist of it:
exports.payout = functions.https.onRequest((request, response) => {
var uid = "nYIAHSYimJMHbMkXqDt9PQ0U3Nf2";
return getPayoutsPending(uid)
.then(array => getPayoutsAmount(array))
.then(value => {
var valueTrunc = parseFloat(Math.round(value * 100) / 100).toFixed(2);
const sender_batch_id = Math.random().toString(36).substring(9);
const sync_mode = 'false';
const payReq = JSON.stringify({
sender_batch_header: {
sender_batch_id: sender_batch_id,
email_subject: "You have a payment"
},
items: [
{
recipient_type: "EMAIL",
amount: {
value: valueTrunc,
currency: "CAD"
},
receiver: "me#gmail.com",
note: "Thank you.",
sender_item_id: "Payment"
}
]
});
return paypal.payout.create(payReq, sync_mode, (error, payout) => {
if (error) {
console.warn(error.response);
response.status('500').end();
throw error;
}
console.info("payout created");
console.info(payout);
return updatePaymentsPending(uid, sender_batch_id)
});
}).then(() => {
response.status('200').end();
return null;
}).catch(error => {
console.error(error);
});
});
I hope this helps.
EDIT: the successful case was missing a return null. I guess your linter is picky about that.
EDIT: un-nested last then().
Also untested but it seems like the goal based on your eslint is to un-nest everything. This gets kind of cumbersome but it's doable, I guess.
exports.payout = functions.https.onRequest((request, response) => {
var uid = "nYIAHSYimJMHbMkXqDt9PQ0U3Nf2";
// Returns paymentRequest
const buildPaymentRequest = (value) => {
return new Promise((resolve) => {
var valueTrunc = parseFloat(Math.round(value * 100) / 100).toFixed(2);
const sender_batch_id = Math.random().toString(36).substring(9);
const sync_mode = 'false';
const payReq = JSON.stringify({
sender_batch_header: {
sender_batch_id: sender_batch_id,
email_subject: "You have a payment"
},
items: [{
recipient_type: "EMAIL",
amount: {
value: valueTrunc,
currency: "CAD"
},
receiver: "me#gmail.com",
note: "Thank you.",
sender_item_id: "Payment"
}]
});
resolve(paymentRequest);
});
}
// Returns payout
const createPayout = (paymentRequest) => {
return new Promise((resolve, reject) => {
paypal
.payout
.create(payReq, sync_mode, (error, payout) => {
if (error) {
console.warn(error.response);
reject(error);
} else {
console.info("payout created");
resolve(payout);
}
});
});
};
getPayoutsPending(uid)
.then(getPayoutsAmount)
.then(buildPaymentRequest)
.then(createPayout)
.then(updatePaymentsPending(uid, sender_batch_id))
.then(() => {
response.status('200').end();
return;
})
.catch((err) => {
console.log(err);
response.status('500').end();
return console.error(error);
})
});
Alternatively, throwing an // eslint-disable at the top of the file would fix your issue ;)
I am having some trouble understanding Javascript promises, specifically chaining them and passing errors up the chain. In the following code:
function myPromise() {
return new Promise((resolve, reject) => {
setTimeout(function() {
console.log('done')
reject('resolved');
}, 1000);
});
}
function myOtherPromise() {
return new Promise((resolve, reject) => {
myPromise().then(done => {
resolve(done);
}).catch(e => {
console.log('In myOtherPromise, caught err: ', e);
reject(e)
});
});
}
myOtherPromise().then(done => {
console.log('done calling myOtherPromise: ', done);
}).catch(e => {
console.log('caught err from myOtherPromise', err);
});
The output shows:
done
In myOtherPromise, caught err: resolved
I don't understand why the following is not printed:
'caught err from myOtherPromise'
I feel like there is something fundamental I am not quite getting. Why doesn't the rejection from myOtherPromise get passed to the final catch block?
You catch the error into the e variable, but output the err variable (which is undefined and causes runtime error).
.catch(e => {
console.log('caught err from myOtherPromise', err);
})
Should be:
.catch(e => {
console.log('caught err from myOtherPromise', e);
})