Fix this without binding - javascript

I want to convert exec function to execAsync
https://github.com/couchbase/couchnode/blob/master/lib/bucket.js#L3257
I do this
couchbase.BucketImpl.LookupInBuilder.prototype.executeAsync = function() {
return new Promise((resolve, reject) => {
this.execute((error, result) => {
if (error instanceof Error) {
reject(error);
} else {
resolve(result);
}
});
});
};
Sometimes I loose this and I don't want bind each time to instance MutateInBuilder
Is it a way that automatically help me? I want always this.execute is couchbase.BucketImpl.LookupInBuilder.prototype.execute

It seems strange that you're overwriting the couchbase prototype... but as #trincot suggests, use fat arrow funtion:
couchbase.BucketImpl.LookupInBuilder.prototype.executeAsync = () => {
return new Promise((resolve, reject) => {
this.execute((error, result) => {
if (error instanceof Error) {
reject(error);
} else {
resolve(result);
}
});
});
};

Related

javascript forEach appears to be nonblocking

Reading other posts here the consensus is the forEach should be synchronous and blocking.
However I must have done something strange in my code because it doesn't appear that way:
var noDupes = false; // should be true but force no inserts for now
console.log('forEach');
courses.forEach((course) =>
{
const promiseNoDupe = new Promise((resolve, reject) =>
{
dbo.collection("courses").findOne({ id: course.id }, (err, result) =>
{
if (err) throw err;
if (result) { console.log('dupe'); return reject('dupe'); }
console.log('nodupe');
resolve('nodupe');
});
});
noDupes &= promiseNoDupe.then(() =>
{
console.log('true promise');
return true;
}).catch(() =>
{
console.log('false promise');
return false;
});
});
console.log('End forEach');
if (noDupes)
{
console.log('Inserting many');
dbo.collection("courses").insertMany(courses, (err, result) =>
{
if (err) return res.status(400).send(error.details[0].message);
res.send(courses);
});
}
else
{
console.log('No Dupes allowed');
res.status(400).send('Inserting duplicate ID not Allowed!');
}
Console output:
forEach
End forEach
No Dupes allowed
nodupe
true promise
nodupe
true promise
The end forEach is executed before the promise is completed and before any of the internal processing is conducted! Subsequently the logic waiting on the promise is processing ahead of time.
I'm not sure what is going wrong but I'm trying to wait for the completion of all checks in the forEach before committing any new records.
Thanks to charlietfl for steering me towards map() and Promise.all().
Here is the working code:
var dupePromises = courses.map((course) =>
{
return new Promise((resolve, reject) =>
{
dbo.collection("courses").findOne({ id: course.id }, (err, result) =>
{
if (err) throw err;
if (result) return reject(false);
resolve(true);
});
}).then(() =>
{
return true;
}).catch(() =>
{
return false;
});
});
Promise.all(dupePromises).then((results) =>
{
if (results.every((isnotDupe) => { return isnotDupe /* == true */ }))
{
dbo.collection("courses").insertMany(courses, (err, result) =>
{
if (err) return res.status(400).send(error.details[0].message);
res.send(courses);
});
}
else{
res.status(400).send('Inserting duplicate ID not Allowed!');
}
});
}

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));

Promise do not bubble outside

I need to test function testMe using Mocha. But there is trouble when my unit test throw an error. Here is simpified example
function testMe(callback) {
new Promise((resolve, reject) => {
setTimeout(() => resolve([1,2,3]), 1000);
}).then((result) => {
callback(null, result);
}).catch((error) => {
callback(error, null)
});
}
testMe((err, result) => {
if(err) throw new Error();
if(result.length < 5) throw new Error();
});
In this example after throw runs catch block. But I need to run catch block only after reject.
EDIT:
In this case the script never stop. I don't understand why.
function testMe(callback) {
new Promise((resolve, reject) => {
setTimeout(() => resolve([1,2,3]), 1000);
}).then((result) => {
callback(null, result);
}, (error) => {
callback(error, null)
}).catch(() => {
console.log('Do not throw an error but still running');
});
}
testMe((err, result) => {
if(err) throw new Error();
if(result.length < 5) throw new Error();
});
When you work with promises then return the promises from functions instead of taking callbacks.
For example, instead of:
function testMe(callback) {
new Promise((resolve, reject) => {
// ...
});
}
use:
function testMe(callback) {
return new Promise((resolve, reject) => {
// ...
});
}
that way you will have the promise available to the caller of the function.
If you need to mix both styles, i.e. returning promises and taking callbacks, consider using a reliable library to handle that for you especially if you have trouble coding the translation between those style yourself:
http://bluebirdjs.com/docs/api/ascallback.html
http://bluebirdjs.com/docs/api/promise.promisify.html
You can simply return the promise from the test:
function testMe() {
// ^^ drop the callback
return new Promise((resolve, reject) => {
// ^^^^^^ return the promise
setTimeout(() => resolve([1,2,3]), 1000);
});
}
var p = testMe().then(result) => {
// ^^^^^ use the promise
if(result.length < 5) throw new Error();
});
return p; // to mocha

How to stop promise chain after resolve?

I want to stop promise chain after it resolved via some conditions. Below code is might useful to understand what am I saying.
function update(id, data) {
return new Promise((resolve, reject) => {
let conn;
pool.get()
.then((db) => {
conn = db;
if(Object.keys(data).length === 0) {
return resolve({ updated: 0 });
}
else {
return generateHash(data.password);
}
})
.then((hash) => {
conn.query("UPDATE ... ", (err, queryResult) => {
if(err) {
throw err;
}
resolve({ updated: queryResult.affectedRows });
});
})
.catch((err) => { ... })
});
}
Note that pool.get() is promise wrapped API for getting connection pool from MySQL module that I made.
What I'm trying to do is updating user data. And for save server resources, I avoided to update if no data to update(Object.keys(data).length === 0).
When I tried this code, second then(updating db) is always happening even if no data to update!
I read this post, but it didn't worked. Why the promise chain wasn't stopped when I called "return resolve();"? And how to I stop it properly? I really like using Promises, but sometimes, this kind of things make me crazy. It will be very appreciate to help me this problem. Thanks!
P.S. I'm using node v6.2.2 anyway.
Why the promise chain wasn't stopped when I called "return resolve();"?
You've returned from the current then callback and fulfilled the outer promise. But that doesn't "stop" anything, then then chain still will continue by resolving with the return value of the callback.
And how to I stop it properly?
You need to put the then call inside the if to have the condition apply to it:
pool.get()
.then((db) => {
…
if (Object.keys(data).length === 0) {
…({ updated: 0 });
} else {
return generateHash(data.password)
.then((hash) => {
conn.query("UPDATE ... ", (err, queryResult) => {
…
});
})
}
})
.catch((err) => { ... })
And in any case, you should avoid the Promise constructor antipattern! You should only promisify the query method:
function query(conn, cmd) {
return new Promise((resolve, reject) => {
conn.query(cmd, (err, queryResult) => {
if (err) reject(err); // Don't throw!
else resolve(queryResult);
});
});
}
and then use that:
function update(id, data) {
return pool.get()
.then(conn => {
if (Object.keys(data).length === 0) {
conn.close(); // ???
return { updated: 0 };
} else {
return generateHash(data.password)
.then(hash => {
return query(conn, "UPDATE ... ")
}).then(queryResult => {
conn.close(); // ???
return { updated: queryResult.affectedRows };
}, err => {
…
conn.close(); // ???
});
}
});
}
Notice that it might not make sense to get a connection from the pool if you can know beforehand that no query will be made, so probably you should put the if on the top level:
function update(id, data) {
if (Object.keys(data).length === 0) {
return Promise.resolve({ updated: 0 });
} else {
return pool.get()
.then(conn => {
return generateHash(data.password)
.then(hash => {
return query(conn, "UPDATE ... ")
}).then(queryResult => {
conn.close(); // ???
return { updated: queryResult.affectedRows };
}, err => {
…
conn.close(); // ???
});
});
}
}
This would be a good situation to use an if statement:
function update(id, data) {
if (Object.keys(data).length === 0) {
return Promise.resolve({ updated: 0 });
}
let conn;
return pool.get()
.then((db) => {
conn = db;
return generateHash(data.password);
})
.then((hash) => {
return new Promise(function (resolve, reject) {
conn.query("UPDATE ... ", (err, queryResult) => {
if(err) {
reject(err);
}
resolve({ updated: queryResult.affectedRows });
});
});
})
.catch((err) => { ... })
}

Using throw in promises

I would like to create a function that returns a promise and if something throws an error within, it returns promise reject.
function promiseFunc(options) {
return new Promise(() => {
return options;
});
}
function myfunc(options) {
return new Promise(() => {
if (!options) throw new Error("missing options");
return promiseFunc(options).then((result) => {
if (result.throwerr) throw new Error("thrown on purpose");
return result.value;
});
});
};
My test as follows:
const myfunc = require("./myfunc");
describe('myfunc', () => {
it('should fail without options', () => {
return myfunc()
.then((result) => { throw new Error(result) }, (err) => {
console.log("test #1 result:", err.message === "missing options");
});
});
it('should fail on options.throwerr', () => {
return myfunc({throwerr: true})
.then((result) => {}, (err) => {
console.log("test #2 result:", err.message === "thrown on purpose");
});
});
it('should return options.value', () => {
return myfunc({value: "some result", throwerr: false})
.then((result) => {
console.log("test #3 result:", result === "some result");
}, (err) => {});
});
});
The first test pass, but the second and third fails.
Log #2 does not even run, so I assumed the "throw on purpose" messes up something, therefore I created test #3, where I don't throw anything, but it still fails.
What am I missing?
Solution:
function promiseFunc(options) {
return new Promise(resolve => {
return resolve(options);
});
}
function myfunc(options) {
return new Promise((resolve, reject) => {
if (!options) throw new Error("missing options");
return promiseFunc(options).then(result => {
if (result.throwerr) throw new Error("thrown on purpose");
return resolve(result.value);
}).catch(err => {
return reject(err);
});
});
};
You forgot to pass a function with resolve and reject parameters, so your promises just don't work.
function promiseFunc(options) {
return new Promise(resolve => { // resolve function
resolve(options)
})
}
module.exports = function myfunc(options) {
return new Promise((resolve, reject) => { // since you may either resolve your promise or reject it, you need two params
if (!options) {
return reject(new Error("missing options"))
}
return promiseFunc(options).then(result => {
if (result.throwerr) {
return reject(new Error("thrown on purpose"))
}
resolve(result.value)
})
})
}
... and the test (mocha)
const assert = require('assert'),
myfunc = require("./myfunc")
describe('myfunc', () => {
it('should fail without options', done => { // mind the callback, promises are always async
myfunc()
.catch(err => {
assert(err.message === "missing options")
done() // <- called here
})
})
it('should fail on options.throwerr', done => {
myfunc({throwerr: true})
.catch(err => {
assert(err.message === "thrown on purpose")
done()
})
})
it('should return options.value', done => {
return myfunc({value: "some result", throwerr: false})
.then(result => {
assert(result === "some result")
done()
})
})
})
I would like to create a function that returns a promise and if something throws an error within, it returns promise reject.
This will do it ...
var q = require('q'); // In recent versions of node q is available by default and this line is not required
function iReturnAPromise(num) {
var def = q.defer();
if (typeof num=== 'number') {
try {
var value = 100 / num;
def.resolve(value);
} catch(e) {
def.reject("oops a division error - maybe you divided by zero");
}
} else {
def.reject("o no its not a number");
}
return def.promise;
}
PS this function was coded freehand and has not been tested - but this will work. Obviously try catch should be used sparingly.
PS I prefer the q library implementation of promise instead of the default node promise library - they take a very different approach. q dispenses with all the wrapping!
using the promise library u wanted ...
function iReturnAPromise(num) {
return new Promise(function(resolve, reject) {
if (typeof num === 'number') {
try {
var value = 100 / num;
resolve(value);
} catch (e) {
reject("oops a division error - maybe you divided by zero");
}
} else {
reject("o no its not a number");
}
})
}
iReturnAPromise(7).then(
function(response) {console.log("success", response)},
function(response) {console.log("failure", response)}
);
// Unexpectedly this is not an error in node 5.6 because div by 0 is not an error operation anymore!
iReturnAPromise(0).then(
function(response) {console.log("success", response)},
function(response) {console.log("failure", response)}
);
iReturnAPromise("fred").then(
function(response) {console.log("success", response)},
function(response) {console.log("failure", response)}
);
you can see why i prefer the q syntax :)

Categories

Resources