is there any method in bluebird which works like async.waterfall - javascript

I am doing something like this in which first function is dependent dependent on second .
let findOrg = () => {
return new Promise((resolve, reject) => {
db.organization.find({
where: data
})
.then(org => {
return resolve(org);
}).catch(err => {
reject(err);
});
}); };
let createOrg = org => {
return new Promise((resolve, reject) => {
if (org) {
return resolve(org);
}
db.organization.build(data)
.save()
.then((org) => {
return resolve(org);
}).catch(err => {
reject(err);
});
}); };
findOrg()
.then(org => { //going to find org
return createOrg(org); //then going to make org
}).then(newOrg => {
res.data(mapper.toModel(newOrg)); //then mapping
}).catch(err => {
return res.failure(err);
});
in both above function findOrg and createOrg new promise (ES6) are created
My ques is --
1. how we can solve this in Bluebird promise library (in sequence if one function is dependent on other) like
async.waterfall([
function(){},
function(){}],
function(){})
here 2 promises are created .is there any way i

You can use bluebird's Promise.reduce or create your own waterfall (chain) function like this as alternative.
But: your code has unnecessary overhead in using the promise constructor antipattern: you can write it without using new Promise, and with .bind you also avoid creating inline functions explicitly, ... like this:
let findOrg = () => db.organization.find({where: data});
let createOrg = org => org || db.organization.build(data).save();
findOrg()
.then(createOrg)
.then(mapper.toModel.bind(mapper))
.then(res.data.bind(res))
.catch(res.failure.bind(res));
This is quite clean in my opinion.

Related

How do I avoid nesting promises in firebase functions? [duplicate]

Given the following function I get the warning:
warning Avoid nesting promises promise/no-nesting (line 6)
How should I re-estructure the function to fix the warning?
function FindNearbyJobs(uid, lat, lng){
return admin.database().ref(`users/${uid}/nearbyjobs`).remove().then(data => {
return new Promise((resolve, reject) => {
const geoQueryJobs = geoFireJobs.query({center: [lat, lng], radius: 3 });
geoQueryJobs.on("key_entered", (key, location, distance) => {
return Promise.all([admin.database().ref(`jobs/${key}/category`).once('value'), admin.database().ref(`users/${uid}/account/c`).once('value')]).then(r => {
const cP = r[0];
const cO = r[1];
if (cO.val().includes(cP.val())){
return admin.database().ref(`users/${uid}/nearbyjobs/${key}`).set({ d: distance });
}else{
return null;
}
});
});
geoQueryJobs.on("ready", () => {
resolve();
});
});
});
}
You have a promise then() call nested inside another promise's then(). This is considered to be poor style, and makes your code difficult to read. If you have a sequence of work to perform, it's better to chain your work one after another rather than nest one inside another. So, instead of nesting like this:
doSomeWork()
.then(results1 => {
return doMoreWork()
.then(results2 => {
return doFinalWork()
})
})
Sequence the work like this:
doSomeWork()
.then(results => {
return doMoreWork()
})
.then(results => {
return doFinalWork()
})
Searching that error message also yields this helpful discussion.

How do I access promise callback value outside of the function?

It is to my understanding that callback functions are asynchronous and cannot return a value like regular functions. Upon reading about promises, I thought I grasped a good understanding about them, that they are basically an enhanced version of callbacks that allows returning a value like asynchronous function. In my getConnections method, I am attempting to call the find() function on my database through mongoose, and I am attempting to grab this array of objects and send it to the views.
var test = new Promise((resolve, reject) => {
Database.find().then(list => {
resolve(list);
}).catch(err=> {
return reject(err);
})
})
console.log(test)
When I attempt to log to the console outside of the promise function, I get Promise { _U: 0, _V: 0, _W: null, _X: null }
I don't think this is functioning correctly, and I thought I utilized promises correctly. Could anyone point me in the right direction on how to return this array of objects outside of the callback function?
You can simply add await before the promise declaration.
i.e.
var test = await new Promise...
The thing is that when you write a function like this:
const getData = async () => { const response = await fetch(someUrl, {}, {}); return response;}
Then you also need to await that function when you call it. Like this:
const setData = async () => { const dataToSet = await getData(); }
let test = new Promise((resolve, reject) => {
Database.find().then(list => {
resolve(list);
}).catch(err=> {
return reject(err);
})
})
test
.then(result=>console.log(result))
Should solve your problem.
var someValue;
var test = await new Promise((resolve, reject) => {
Database.find().then(list => {
resolve(list);
}).catch(err=> {
return reject(err);
})
}).then(res => {
someValue=res;
})
console.log(someValue);

Querying multiple promises with a callback

In node.js i have a databaseMapper.js file, that uses the Ojai node MapR api. to extract data. So far i have it working with single documents, but since this is an async api, i have a bit of issues with querying multiple documents.
This is what i have so far:
function queryResultPromise(queryResult) {
//this should handle multiple promises
return new Promise((resolve, reject) => {
queryResult.on("data", resolve);
// ...presumably something here to hook an error event and call `reject`...
});
}
const getAllWithCondition = async (connectionString, tablename, condition) =>{
const connection = await ConnectionManager.getConnection(connectionString);
try {
const newStore = await connection.getStore(tablename);
const queryResult = await newStore.find(condition);
return await queryResultPromise(queryResult);
} finally {
connection.close();
}
}
here it will only return the first because queryResultPromise will resolve on the first document.. however the callback with "data" may occur multiple times, before the queryResult will end like this queryResult.on('end', () => connection.close())
i tried using something like Promise.all() to resolve all of them, but I'm not sure how i include the queryResult.on callback into this logic
This will work
const queryResultPromise = (queryResult) => {
return new Promise((resolve, reject) => {
let result = [];
queryResult.on('data', (data) => {
result.push(data)
});
queryResult.on('end', (data) => {
resolve(result);
});
queryResult.on('error', (err) => {
reject(err);
})
});
};

How to define a promise chain without using then method

I already looked for similar questions, but they are related to JQuery or any other library.
First, I wrote this:
const printIn1Sec = (value) => {
return new Promise(resolve => {
setTimeout(() => {
console.log(value);
resolve();
}, 1000)
});
};
And used it in this way:
printIn1Sec(1)
.then(() => printIn1Sec(2))
.then(() => printIn1Sec(3));
I think then is very important, because it allows us to execute something as soon as the promise is resolved.
But I was looking for something like this:
printIn1Sec(1)
.printIn1Sec(2)
.printIn1Sec(3);
I noticed I needed an object with access to this printIn1Sec method. So I defined a class:
class Printer extends Promise {
in1Sec(v) {
return this.then(() => this.getPromise(v));
}
getPromise(value) {
return new Printer(resolve => {
setTimeout(() => {
console.log(value);
resolve();
}, 1000)
})
}
}
And used it this way:
Printer.resolve().in1Sec(1).in1Sec(2).in1Sec(3);
I had to resolve the Promise from the beginning, in order to the start the chain. But it still bothers me.
Do you think, is there a way to get it working like the following?
printIn1Sec(1).printIn1Sec(2).printIn1Sec(3);
I was thinking in a new class or method, that could receive these values, store them, and finally start resolving the chain.
But it would require to call an aditional method at the end, to init with the flow.
If you really wanted to create a chainable interface as in your question, this would do it:
const printIn1Sec = (function() {
function setTimeoutPromise(timeout) {
return new Promise(resolve => setTimeout(resolve, 1000));
}
function printIn1Sec(value, promise) {
const newPromise = promise
.then(() => setTimeoutPromise(1000))
.then(() => console.log(value));
return {
printIn1Sec(value) {
return printIn1Sec(value, newPromise);
},
};
}
return value => printIn1Sec(value, Promise.resolve());
}());
printIn1Sec(1)
.printIn1Sec(2)
.printIn1Sec(3);
We just hide all the promise creation and chaining in an internal function. I split the code into smaller functions to make it a bit nicer looking.
You can try async and await
const printIn1Sec = (value) => {
return new Promise(resolve => {
setTimeout(() => {
console.log(value);
resolve();
}, 1000)
});
};
async function fun(){
await printIn1Sec(1);
await printIn1Sec(2);
await printIn1Sec(3);
}
fun();

How to flatten a Promise within a Promise?

I have the following 2 functions, each returns a Promise:
const getToken = () => {
return new Promise((resolve, reject) => {
fs.readFile('token.txt', (err, data) => {
if (err) { return reject(err) }
if (!tokenIsExpired(data.token)) {
return resolve(data.token)
} else {
return requestNewToken()
}
})
})
}
const requestNewToken = () => {
return new Promise((resolve, reject) => {
restClient.get(url, (data, res) => {
fs.writeFile('tokenfile.txt', data.token, err => {
resolve(data.token)
})
})
})
}
function1()
.then(value => {
console.log('taco')
})
.catch(err => {
console.log(err)
})
So function1 runs, and (depending on some condition), it sometimes returns function2, which is returning another Promise. In this code, when function2 is called, the console.log('taco') never runs. Why is this? I thought that if you return a Promise from within a Promise, the resolved value of the nested Promise is what is resolved at the top level.
In order for me to get this to work, I have to do this:
const getToken = () => {
return new Promise((resolve, reject) => {
if (!tokenIsExpired()) {
return resolve(getToken())
} else {
return requestNewToken ()
.then(value => {
resolve(value)
})
}
})
}
That works, but it seems like I'm doing something wrong. It seems like there should be a more elegant way to handle/structure this.
You're right that promises auto-unwrap, but in this case you're returning from inside a promise constructor, which is ignored, you need to invoke either resolve or reject instead of using return. I think this might be the solution you're looking for:
const function1 = () => {
return new Promise((resolve, reject) => {
if (someCondition) {
resolve('foobar')
} else {
resolve(function2());
}
})
}
Inside a promise constructor, you need to call resolve or reject, which are equivalent to using return or throw from inside a then callback.
If you find this distinction confusing (I do), you should avoid the promise constructor entirely by just beginning a new chain with Promise.resolve, like this:
const function1 = () => {
return Promise.resolve().then(() => {
if (someCondition) {
return 'foobar';
} else {
return function2();
}
})
}
const function2 = () => {
return new Promise((resolve, reject) => {
resolve('hello world')
})
}
someCondition = false;
function1()
.then(value => {
console.log(value)
})
With your updated code, I recommend using a library to wrap APIs, rather than accessing the promise constructor yourself. For example, using bluebird's promisify:
const bluebird = require('bluebird');
const readFile = bluebird.promisify(fs.readFile);
const writeFile = bluebird.promisify(fs.writeFile);
const getUrl = bluebird.promisify(restClient.get, {multiArgs:true});
const getToken = () => {
return readFile('token.txt')
.then((data) => {
if(!tokenIsExpired(data.token)) {
return data.token;
} else {
return requestNewToken();
}
});
};
const requestNewToken = () => {
return getUrl(url)
.then(([data, res]) => {
return writeFile('tokenFile.txt', data.token)
.then(() => data.token);
});
};
I've remained faithful to your source code, but I'll note there may be a bug to do with writing data.token, and later trying to read the token property in that file.
Why use a library instead of the Promise constructor?
It allows you to write code which deals only with promises, which is (hopefully) easier to understand
You can be confident that callback APIs are correctly converted without losing errors. For example, if your tokenIsExpired function throws an error, using your promise constructor code, it would be lost. You would need to wrap all of your inner callback code in try {} catch(e) {reject(e)}, which is a hassle and easily forgotten.

Categories

Resources