Promise do not bubble outside - javascript

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

Related

Retry functionality in promise chain

i have a promise chain
If i receive error in getServiceCost I want to repeat the chain again (retry) for 2 times how can i achieve this when using Promise chain , meaning again execute getUser, getServiceCost
getUser(100)
.then(getServices)
.then(getServiceCost)
.then(console.log);
function getUser(userId) {
return new Promise((resolve, reject) => {
console.log('Get the user from the database.');
setTimeout(() => {
resolve({
userId: userId,
username: 'admin'
});
}, 1000);
})
}
function getServices(user) {
return new Promise((resolve, reject) => {
console.log(`Get the services of ${user.username} from the API.`);
setTimeout(() => {
resolve(['Email', 'VPN', 'CDN']);
}, 3 * 1000);
});
}
function getServiceCost(services) {
return new Promise((resolve, reject) => {
console.log(`Calculate the service cost of ${services}.`);
setTimeout(() => {
resolve(services.length * 100);
}, 2 * 1000);
});
}
If i receive error in getServiceCost I want to repeat the chain again (retry) for 2 times how can i achieve this when using Promise chain , meaning again execute
getUser, getServiceCost
I'd use an async function (all modern environments support them, and you can transpile for obsolete environments), which lets you use a simple loop. Perhaps as a utility function you can reuse:
async function callWithRetry(fn, retries = 3) {
while (retries-- > 0) {
try {
return await fn();
} catch (error) {
if (retries === 0) {
throw error;
}
}
}
return new Error(`Out of retries`); // Probably using an `Error` subclass
}
Using it:
callWithRetry(() => getUser(100).then(getServices).then(getServiceCost))
.then(console.log)
.catch(error => { /*...handle/report error...*/ });
Or
callWithRetry(async () => {
const user = await getUser(100);
const services = await getServices(user);
return await getServiceCost(services);
})
.then(console.log)
.catch(error => { /*...handle/report error...*/ });

What is the proper way to use Promise.reject with javascript

I have this following piece of code
new Promise((resolve, reject) => {
resolve(apiRequest(data))
reject(console.log('Error'))
}).then(response)
Both methods (resolve and reject) are being fired but I want to call reject only when something goes wrong.
How can I throw an error if something goes wrong on that case?
I checked that but it seems like I can not use an If statement to do that check.
new Promise((resolve, reject) => {
const printResult = apiRequest(data)
console.log(printResult) //Outputs Promise {<pending>}
resolve(printResult) //Then it works
reject(console.log('Error'))
}).then(response)
What would be the correct approach to reject a promise?
The easiest way would be with an if condition. i.e
new Promise((resolve, reject) => {
// do something...
if(somethingGoodHappened) {
resolve(data)
} else {
reject(error)
}
})
But usually when dealing with async requests, the thing you are calling will often be returning a promise, so you can attach the then and catch callbacks there.
apiRequest(data)
.then((result) => {
// all good
})
.catch((err) => {
console.log(err)
})
const mock_api = () => new Promise((res, rej) => {
const number = Math.floor((Math.random() * 100) + 1);
setTimeout(() => {
if (number%2==0) return res('randomly RESOLVED')
return rej('randomly REJECTED')
}, 2000)
})
const async_promise = () => new Promise(async (resolve, reject) => {
try {
const resolvedPromise = await mock_api()
resolve(resolvedPromise)
} catch (e) {
reject(e)
}
})
const classicPromise = () => new Promise((resolve, reject) => {
mock_api()
.then(resolve)
.catch(reject)
})
const makeAsyncRequest = async () => {
try {
const data = await async_promise()
console.log('ASYNC AWAIT RESOLVE', data)
} catch (e) {
console.log('ASYNC AWAIT ERR', e)
}
}
makeAsyncRequest()
classicPromise()
.then(r => console.log('PROMISE CHAIN RESOLVE', r))
.catch(e => console.log('PROMISE CHAIN ERR', e))
Because of you resolve before reject so it cannot run into reject,
You can use:
if (printResult) {
resolve(printResult)
} else {
reject(console.log('Error'))
}
You can catch exceptions and return them as rejected Promises
function asyncFunc() {
try {
doSomethingSync();
return doSomethingAsync()
.then(result => {
ยทยทยท
});
} catch (err) {
return Promise.reject(err);
}
}
Always check for err if there is any err return a promise (example below)
// Return new promise
return new Promise(function(resolve, reject) {
// Do async job
request.get(options, function(err, resp, body) {
if (err) {
reject(err);
} else {
resolve(JSON.parse(body));
}
})
})

Fix this without binding

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

Promise.then() but functions run async

I'm new to Javascript and doing a crawler, I've created 4 Promise as these
var openConfig = new Promise((resolve, reject) => {
fs.readFile('./config.json', (err, data) => {
if (err) throw err;
config = JSON.parse(data);
client = new MsTranslator({
client_id: config.translatorId,
client_secret: config.translatorSecret
}, true)
resolve();
})
})
var openFile = new Promise((resolve, reject) => {
console.log('Opening file...')
fs.readFile('./writing/writing.json', (err, data) => {
if (err) throw err;
writing = JSON.parse(data);
console.log('Done parsing file');
resolve();
})
})
var ask = new Promise((resolve, reject) => {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
rl.question('Which lesson do you want to add? ', (ans) => {
lessonId = ans;
rl.close();
resolve();
})
})
var createLesson = new Promise((resolve, reject) => {
console.log('Now processing lesson ' + lessonId);
})
then call the first Promise
openConfig
.then(() => {
return openFile;
})
.then(() => {
return ask;
})
.then(() => {
return createLesson;
})
but as I run, the console show
Opening file...
Which lesson do you want to add? Now processing lesson undefined
Done parsing file
which I understood as my promises are wrong and my function run async. Can you help me to fix this?
Thank you.
Promises are not "called". In your then chain, you only sequentially await them - but the tasks were already started when you created the promises. If you want to sequence the actions, put them in functions.
Btw, your code contains multiple typical mistakes. Don't use global variables, and always promisify at the lowest possible level:
function openFile(path) {
return new Promise((resolve, reject) => {
fs.readFile('./config.json', (err, data) => {
if (err) reject(err); // never `throw err` in non-promise callbacks!
else resolve(data);
});
});
}
function openJSON(path) {
return openFile(path).then(JSON.parse);
}
function openConfig(path) {
return openJSON(path).then(config =>
new MsTranslator({
client_id: config.translatorId,
client_secret: config.translatorSecret
}, true)
)
}
function ask(question) {
return new Promise((resolve, reject) => {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
rl.question(question, ans => {
rl.close();
resolve(ans); // always resolve to *something*
});
});
}
readConfig('./config.json')
.then(client => {
console.log('Opening file...')
return openJSON('./writing/writing.json');
})
.then(writing => {
console.log('Done parsing file');
return ask('Which lesson do you want to add? ');
})
.then(lessonId => {
console.log('Now processing lesson ' + lessonId);
});
Instead of assigning new Promises to vars (these run as soon as created), you should wrap them into functions, which in turn return a new Promise
To help you understand here's a simplified example:
function p1 (data) {
return new Promise(function (resolve, reject) {
resolve(Object.assign(data, {a:1}));
});
}
function p2 (data) {
return new Promise(function (resolve, reject) {
resolve(Object.assign(data, {b:2}));
});
}
function p3 (data) {
return new Promise(function (resolve, reject) {
resolve(Object.assign(data, {c:3}));
});
}
p1({z:0})
.then(p2)
.then(p3)
.then((data)=>console.log(data))
This results in { z: 0, a: 1, b: 2, c: 3 }
See here if you wish to experiment a bit with the above: https://repl.it/DwNB/0
On a separate note, if you are using promises, you should also handle errors in the chain in a final .catch() instead of synchronously throwing midway. That's what the reject callback is for!

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