bluebird .all() does not call .then - node.js

I have an unknown number of async processes that might run from a request. There is a block of text to be modified by these processes.
UpdateScript is called with the text to be modified, it has a callback that I would like to run when everything is complete.
var promise = require('bluebird');
function updateScript(text, cb){
var funcChain = [],
re = some_Regular_Expression,
mods = {text: text};
while (m = re.exec(mods.text)) {
// The text is searched for keywords. If found a subprocess will fire
....
funcChain.push( changeTitleAsync(keyword, mods) );
}
promise.all(funcChain)
.then(function(){
// This is never called.
cb(mods.text);
});
}
function changeTitle(encryptedId, mods){
try{
// database request modifies mods.text
}catch(e){
throw e;
}
}
var changeTitleAsync = promise.promisify(changeTitle);
The changeTitle code is called but the "then" call is not

Partly the problem is incorrect use of promisify(). This is meant to convert a node-style function that takes a callback as it's last argument into one that returns a promise (see docs here).
Instead what you can do with your function above is have it return a new Promise manually like this:
function changeTitle(encryptedId, mods) {
return new Promise(function(resolve, reject){
try {
// do something then resolve promise with results
var result = ...
resolve(result)
} catch (e) {
// reject the promise with caught error
reject(e)
}
})
}
HOWEVER
There is one mistake above: I assume the db call to update the text is also asynchronous, sothe try /catch block will never catch anything because it will run through just as the db kicks off intially.
So what you would have to do is promisify the DB call itself. If you're using a node db library (like Mongoose, etc) you could run Promise.promisifyAll() against it, and use the Async versions of the functions (see promisifyAll section on above link for details).
Hope this helps!!

Related

Error: Transaction rejected with non-error: undefined

I am using knex npm version 0.15.2. while Rollback the transaction I'm getting the following error:
Error: Transaction rejected with non-error: undefined
Trx.rollback()
above function used for rollback.
Same code working for knex version 0.12.6
This is the function I used for commit/Rollback.
function Commit(pTrx, pIsCommit, pCallback) {
try {
var co = require("co");
var q = require('q');
var Q = q.defer();
co(function* () {
if (pIsCommit) {
yield pTrx.commit();
} else {
yield pTrx.rollback();
}
Q.resolve(pCallback('SUCCESS'));
}).catch(function (error) {
Q.reject(pCallback(error));
});
return Q.promise;
} catch (error) {
console.log(error)
}
}
This code could use some work. :) Here are a few things that pop out:
You don't need co or q anymore. Promises and async/await are built-in and much simpler to use. Async functions automatically return promises that will be resolved with the value returned or rejected if an error is thrown. Learn about async/await here: https://jsao.io/2017/07/how-to-get-use-and-close-a-db-connection-using-async-functions/
You shouldn't return success as a string. If the function completes without throwing an exception, then success is implied. I see people do this from time to time, but it's often for the wrong reasons.
You shouldn't accept callback in a function that returns a promise, it should be one or the other. The caller of your function will either pass a callback or await it's completion.
If you are going to use callbacks, then you should return null as the first parameter when successful. See the last sentence here: https://nodejs.org/en/knowledge/getting-started/control-flow/what-are-callbacks/
Your function name, Commit, starts with an uppercase. This convention is typically used to indicate that the function is a contstructor function and meant to be invoked with the new keyword.
Here's how the function could look once cleaned up:
async function commit(pTrx, pIsCommit) {
// Not using a try/catch. If an error is thrown the promise returned will be rejected.
if (pIsCommit) {
await pTrx.commit();
} else {
await pTrx.rollback();
}
// Not going to return anything. If we get to this point then success is implied when the promise is resolved.
}
A consumer of your function would call it with something like:
async function myWork() {
// do work; get pTrx
try {
await commit(pTrx, true);
// If I get here, then I can assume commit was successful, no need to check a return value of 'SUCCESS'
} catch (err) {
// handle error
}
}
It's hard to say where the issue is with the code in its current state. However, if the issue truly is with Knex, then you should probably post this as an issue in the Knex repo: https://github.com/tgriesser/knex/issues But you should write a reproducible test case that proves its an issue with Knex.

How to fix - Promise { <pending> } in Node.js and use it as variable anywhere

I'm accessing google API for converting coordinates into detailed objects using node-geocoder library from npmjs. Everything went well and I'm getting the expected object from geocoder API. The problem started the moment when I thought of using the data outside the promise function. I want to use the values outside the promise/async-await function.
Below is the code I've tried, Pls take a look and help me. TIA...
function goecoderPromiseFunction() {
return new Promise(function (resolve, reject) {
geocoder.reverse({ lat: 45.767, lon: 4.833 })
.then(data => {
cityName = data[0].city;
resolve(cityName);
})
.catch(err => {
console.log(err);
});
});
}
async function app() {
var a = await goecoderPromiseFunction();
return a;
}
var a = app();
console.log("a->", a);
I expect the variable "a" should print the city name "Lyon", but it prints
a-> Promise { < pending > }
The promise returned by the app function is never consumed, that is why it remains in a pending state.
Call then on the app function to get the result :
app().then(a => console.log("a->", a));
You can also use async/await :
(async function() {
var a = await app();
console.log("a->", a);
})();
An asynchronous function actually returns a promise that 'resolves' to the function's return value. You are therefore assigning a promise to the value of a. If you are in the global scope, you obviously cannot use async/await so you need to use either a self-executing async function or you need to run
a.then(data => console.log('a->', data));
to get what you are looking for.
Find out more about async functions here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
It prints because console.log("a->", a); runs while promise haven't returned answer for a variable "a"
Note: you haven't used reject function, if there is an error you wont notice and may be that error was the required answer to be carried by variable "a" that's why it still pending i.e still waiting.
For more idea try to use reject function inside the catch block example reject(err)
instead of console it out as you've done

I have a function with chained promises after which I want to return an integer value but I get undefined before function is resolved

I have created a function that downloads a PDF then reads it and finds the number of pages with chained promises. I want to return the value of the pages when this function is called.
However when I write var b = await ExtractLength(url, destinationFolder,filename); in my main function then console.log(b) I am getting a value of undefined. If I understand correctly the variable b is assigned the value before the promises are resolved. I have tried some alternatives but I don't understand what the problem is. Why is this happening and how I can fix it?
Here is my function:
async function ExtractLength(url, destination, flnm){
var options ={
directory: destination,
filename: flnm
}
await download(url, options, async function(error){
if (error){
console.log("Download error: ", error);
return null;
}
await fs.readFile(destination+flnm, async function(err,dataBuffer){
if (err){
console.log("Read file error: ", err);
return null;
}
await pdf(dataBuffer).then(function(data){
console.log("Number of pages: ", data.numpages);
return data.numpages;
})
.catch(function(erro){
console.log("Pdf error: ",erro);
return null;
});
});
});
}
Your code here is a bit of an antipattern. You usually shouldn't be using both a callback and a Promise. JS async and await are used to get the result of a promise into a variable. For example const x = await Promise.resolve(5); // x = 5
I believe AWS does support both callbacks and promises so just choose one or the other. It looks like you have a good handle on callbacks so the simplest way would probably be removing any async and await keywords. Promises are definitely worth learning!
It would be easier to give a definite solution using the two approaches if you showed us where the download function comes from.
Change the following lines
await download(url, options, async function(error){
await fs.readFile(destination+flnm, async function(err,dataBuffer){
await pdf(dataBuffer).then(function(data){
to have returns like so
return await download(url, options, async function(error){
return await fs.readFile(destination+flnm, async function(err,dataBuffer)
return await pdf(dataBuffer).then(function(data){
You must return a value for your Extract, your readfile function, and your pdf function calls.
To further explain: in each of those chained calls, you're passing anonymous functions for them call, and even though each anonymous function returns a value, you never assign the final value to anything within the Extract call that kicks it all off.

shopify-api-node: promise not returning value

Setting up a node.js app to retrieve order(s) information from shopify. I'm trying to store that data and run some logic, but I can't seem to get a hold of it.
THIS WORKS:
shopify.order.list()
.then(function(orders){
console.log(orders);
});
THIS DOES NOT WORK:
var orders_json;
shopify.order.list()
.then(function(orders){
orders_json=orders;
//console.log(orders);
});
console.log(orders_json); //returns undefined
Let me introduce you to the world of async/await. As long as you declare your function as async and the function you are "awaiting" returns a promise, you can handle this in a more synchronous way. Have a look at the docs linked above. Notice how I called the async function after it was declared. You can't call await outside the scope of an async function.
async function fetchOrders() {
try {
const orders_json = await shopify.order.list();
// do stuff with orders_json
return orders_json;
} catch(err) {
// handle err
}
}
const orders = fetchOrders();

Manually promisifying pg.connect with Bluebird

I want to promisify node-postgres' pg.connect method along with the inner connection.query method provided in the callback.
I can .promisify the latter, but I need to implement the first one manually (if I'm missing something here, please explain).
The thing is, I'm not sure if this code is correct or should be improved? The code is working, I just want to know if I'm using Bluebird as meant.
// aliases
var asPromise = Promise.promisify;
// save reference to original method
var connect = pg.connect.bind(pg);
// promisify method
pg.connect = function (data) {
var deferred = Promise.defer();
connect(data, function promisify(err, connection, release) {
if (err) return deferred.reject(err);
// promisify query factory
connection.query = asPromise(connection.query, connection);
// resolve promised connection
deferred.resolve([connection,release]);
});
return deferred.promise;
};
Throw all that horrible callback code away, then do this somewhere in your application initialization:
var pg = require("pg");
var Promise = require("bluebird");
Object.keys(pg).forEach(function(key) {
var Class = pg[key];
if (typeof Class === "function") {
Promise.promisifyAll(Class.prototype);
Promise.promisifyAll(Class);
}
})
Promise.promisifyAll(pg);
Later in anywhere you can use the pg module as if it was designed to use promises to begin with:
// Later
// Don't even need to require bluebird here
var pg = require("pg");
// Note how it's the pg API but with *Async suffix
pg.connectAsync(...).spread(function(connection, release) {
return connection.queryAsync("...")
.then(function(result) {
console.log("rows", result.rows);
})
.finally(function() {
// Creating a superfluous anonymous function cos I am
// unsure of your JS skill level
release();
});
});
By now there are a number of libraries which do this for you:
pg-promise - generic Promises/A+ for PG
postgres-bluebird
dbh-ph
pg-bluebird
Update for bluebird 3:
The pg.connectAsync(...).spread(function(connection, release) { ... }) call will not work anymore, because the API of bluebird has changed: http://bluebirdjs.com/docs/new-in-bluebird-3.html#promisification-api-changes .
The problem is that promisifyAll in bluebird 3 does not handle multiple arguments by default. This results in the .spread() call reporting a TypeError like the following:
TypeError: expecting an array or an iterable object but got [object Null]
To solve this, you can explicitly enable multiple arguments for connect / connectAsync. Do the following after all the promisifying stuff mentioned above:
...
pg.connectAsync = Promise.promisify(pg.connect, { multiArgs: true });
I suggest to modify Petka Antonov solution a bit
var Promise = require('bluebird');
var pg = require('pg');
Object.keys(pg).forEach(function (key) {
var Cls = null;
try {
Cls = pg[key];
if (typeof Cls === 'function') {
Promise.promisifyAll(Cls.prototype);
Promise.promisifyAll(Cls);
}
} catch (e) {
console.log(e);
}
});
Promise.promisifyAll(pg);
here 'pg[key] wrapped up in try-catch block because pg[key] can retrun error when attempt to access pg['native']

Resources