I cannot create a new Observable object out of the callback function, for example converting glob function to Observable stream:
const stream$ = fromCallback(() => glob('src/**/*.ts'));
const fromCallback = (cbWrapper) => {
const cb = cbWrapper();
const args = cb.arguments;
return Observable.create(observer => {
args.push((err, data) => {
if(err) {
observer.error(err);
} else {
observer.next(data);
}
observer.complete();
});
cb.call(null, args);
};
This is more or less what I want to do - create a fromCallback function which accepts my function in a wrapper, adds a new parameter which is a callback handler, and calls observer based on the results. But it doesn't work - the cbWrapper() returns always true for some reason.
What's wrong here? Is there a better solution to solve this?
Related
I am a little bit confused with the code below. It's obviously a two arrow function written in es6 code but I do not understand exactly some parts.
The 2nd parameter named done is an empty function that does nothing? Or it is executed with a simple return as the result from the second arrow anonymous function?
the XXXX.load is a promise function that returns some results. How the caller of the Index can get the results of the 2nd parameter done ie done(null, result) ?
What is the equivalent code in es5?
const Index = (name, done = () => {}) => (dispatch, getState) => {
return XXXX.load()
.then((result) => {
dispatch({type:OK});
done(null, result);
})
.catch((error) => {
dispatch({type:ERROR});
done(error);
});
};
Let's go one by one:
Index (name, done = () => {}) defines a default value for done in case none is provided when Index is called. This helps down to road to not do any checks in case done is null/undefined. You could also write it like this
const Index = (name, done) => (dispatch, getState) => {
if (!done) {
done = () => {}
}
}
The caller will just pass a function as the second argument when calling Index.
A general note: Index actually returns a function that will expect a dispatch and/or a getState param.
The 2nd parameter named done is an empty function that does nothing?
It's a parameter. It takes whatever value you give it.
The default value, which is assigned if the caller doesn't pass a second argument, is a function that does nothing. This lets it be called without throwing an undefined is not a function error or having an explicit test to see if it is a function or not.
How the caller of the Index can get the results of the 2nd parameter done ie done(null, result) ?
By passing its own function as the second argument.
What is the equivalent code in es5?
var Index = function(name, done) {
if (!done) done = function() {};
return function(dispatch, getState) {
return XXXX.load()
.then(function(result) {
dispatch({
type: OK
});
done(null, result);
})
.catch(function(error) {
dispatch({
type: ERROR
});
done(error);
});
}
};
The empty function is a default value for done. Default values prevents runtime crashes.
2 and 3 can be understood by seeing below code: (simply run it and see the consoles.
const DEFAULT_FUNCTION_VALUE = ()=> {};
const XXXX = {
load: function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve({data: 'from XXXX.load'});
},2000);
});
}
}
const Index = function(name='', done=DEFAULT_FUNCTION_VALUE) {
return function(dispatch, getState) {
return XXXX.load().then(function(result) {
console.log({result});
done(result);
}).catch(function(error) {
console.log(error);
});
}
}
function doneImplementation(data) {
console.log('Data from done- ', data);
}
Index('', doneImplementation)();
I have the following code:
class simplePromise {
constructor(resolveFn, rejectFn) {
console.log(resolveFn, 'resolveFn') // (resolutionFunc, rejectionFunc) => {
// resolutionFunc(777);
// rejectionFunc();
// }
console.log(rejectFn, 'rejectFn') //undefined
}
}
const promise1 = new simplePromise( (resolutionFunc, rejectionFunc) => {
resolutionFunc(777);
rejectionFunc();
});
As you can see, I'm trying to pass in 2 functions to the constructor. However, when I console.logged each of them out, I noticed that both functions are registered as 1 argument. In this case, how do I separate the 2 functions?
Are you sure that you want to pass 2 functions to the constructor?
const promise1 = new simplePromise( (resolutionFunc, rejectionFunc) => {...}
this part of your code looks more like you want a single callback function that recieves 2 functions.
Like this:
class SimplePromise {
constructor(callback) {
const resolveFn = (value) => {
console.log("resolved with value", value);
};
const rejectFn = (error) => {
console.log("rejected with error", error);
}
callback(resolveFn, rejectFn);
}
}
const promise1 = new SimplePromise((resolutionFunc, rejectionFunc) => {
console.log('resolutionFunc', resolutionFunc)
console.log('rejectionFunc', rejectionFunc) //undefined
resolutionFunc(777);
rejectionFunc();
});
Not that this code has anything to do with a Promise, but you should study the following structure:
class simplePromise{
constructor(resolveFn, rejectFn){
this.prop1 = 'prop1value'; this.prop2 = 'prop2value';
resolveFn.call(this, 'Passing to first function argument'); // calling in simplePromise context
rejectFn.call(this, 'Passing to second function argument');
}
}
const promise1 = new simplePromise(function(funcOneArg){
console.log(funcOneArg);;
console.log("this.prop1 = '"+this.prop1+"';"); // see why `.call(this` is in `constructor`
console.log("this.prop2 = '"+this.prop2+"';");
},
function(functionTwoArg){
console.log('-'.repeat(45));
console.log(functionTwoArg);
});
So when you pass the arrow function to the new simplePromise constructor, that entire function is the first argument (resolveFn). In order to instantiate this the way you want, you need to define the resolutionFunc and rejectionFunc and then do it like so:
const resolutionFunc = () => {do stuff}
const rejectionFunc = () => {do stuff}
const promise1 = new simplePromise(resolutionFunc, rejectionFunc)
Please help trying to get this function to return value back to my main process. currently everything shows in the console however if I return the object its blank or undefined
const GetSelectDeviceFromDB = () => {
db.all("SELECT * FROM device_list", function (err, rows) {
rows.forEach(function (row) {
console.log(row.device);
return row.device;
});
});
};
module.exports = { GetSelectDeviceFromDB };
OUPUTS:
console.log =. { device1, device2 }
return = undefined and if I add the return to the beginning of the sql statement I get {}
Since all() method is asynchronous and it is using a callback, you can turn your method into a method like this:
const GetSelectDeviceFromDB = () => new Promise((resolve, reject) => {
db.all('SELECT * FROM device_list', (err, rows) => {
if (err) {
reject(err);
}
const devices = rows.map((row) => row.device);
resolve(devices);
});
});
It will return a Promise, so you can call it like this:
GetSelectDeviceFromDB().then(devices => { ... })
Returning from forEach isn't a good idea, returning from another object's method (db.all in you case) isn't either. You need to return exactly in the first scope of the lambda function, somewhere outside of db.all(...). But in this case it's an async method, so you should make your whole function async or a Promise
How can I achieve dynamic callback arguments in JavaScript
I have a three functions I want to compose. Why am I doing this is because I want to encapsulate the details of the initDB so I can write less code. Here's what it looks like below:
const initDB = (schemas: any[]) =>
Realm.open({ path: 'CircleYY.realm', schema: schemas })
.then((realm: Realm) => ({ realm }))
.catch((error: Error) => ({ error }));
So basically this function just initialize a DB and it will return a DB instance or an Error.
I also have some specific database write functions like this below:
// Delete a message
const deleteOrder = (orderID: string, realm: Realm) => {
realm.write(() => {
const order = realm.objects('Orders').filtered(`primaryKey = ${id}`);
realm.delete(order);
});
};
and I have this three functions below:
makeDBTransaction(deleteOrder(id));
and
makeDBTransaction(writeCommentInOrder(orderId, comment))
and
const makeDBTransaction = async (callback: Function) => {
const { error, realm } = (await initDB([
OrderSchema,
ProductSchema,
])) as InitRealm;
if (error) return { error };
callback(realm); // Pass realm while maintaining the arguments specified in the callback which is dynamic
return realm.close();
};
I also want to pass the realm into the callback that can have more than 2 arguments.
How can I achieve that?
I think you can keep adding arguments in an array in a required order and then apply the arguments to the function and call that function.
//for example
function foo1(x, y) {
console.log(x,y);
}
function foo2(cb, y) {
const x = 3;
cb.apply(null, [x,y]);
}
foo2(foo1, 5);
//So your code will be like this
makeDBTransaction(deleteOrder, [id]);
const makeDBTransaction = async (callback: Function, arg: any[]) => {
const { error, realm } = (await initDB([
OrderSchema,
ProductSchema,
])) as InitRealm;
if (error) return { error };
arg.push(realm);
callback.apply(null, arg);
return realm.close();
};
I have a function working perfectly well within a node environment. The function uses promises, with S3 calls and a then and catch to call the callback with relevant 200/500 statusCode and a message body in each of them.
Now I am deploying it as a lambda function with a wrapper around it looking like this:
module.exports.getAvailableDates = (event, context, callback) => {
const lambdaParams = retrieveParametersFromEvent(event);
console.log(`Got the criteria`);
module.exports.getFilteredDates(lambdaParams.startDate,
lambdaParams.endDate, callback);
console.log(`Returning without the internal function results`);
};
The internal function looks like this:
module.exports.function getFilteredDates(startDate, endDate) {
const dateSet = new Set();
return new Promise((resolve, reject) => {
const getAllDates = (isDone) => {
if (isDone) {
const Dates = Array.from(dateSet).join();
resolve(Dates);
return;
}
getTestedDates(startDate, endDate, region, func, memory,
lastDateKey, dateSet).then(getAllDates).catch((error) => {
reject(error);
});
};
lastDateKey = '';
getTestedDates(startDate, endDate, region, func, memory,
lastDateKey, dateSet).then(getAllDates).catch((error) => {
reject(error);
});
});
}
And the even more internal function looks similar, only it actually queries the S3 database and returns the list of keys from it that match the date criteria.
In the AWS CloudWatch logs I see the two prints and only after them the internal function output. My understanding is that the lambda function is not waiting for the internal function with the promises to actually do its work (including the internal waiting on the promises) and returns with a bad status to me. What can I do?
Your last console.log is executed before the callback is executed.
If you want to print the complete statement just before exiting the Lambda, you need to wrap the callback ad wait for the Promise to complete:
import getFilteredDates from '../path/to/file';
module.exports.getAvailableDates = (event, context, callback) => {
const lambdaParams = retrieveParametersFromEvent(event);
console.log(`Got the criteria`);
getFilteredDates(lambdaParams.startDate,lambdaParams.endDate)
.then( result => {
console.log(`Returning the internal function results`);
return callback();
})
.catch(callback);
};
I've update the code to work with Promises given the function below.
Your getFilteredDates needs to be reshaped a bit:
Either you to have a third argument to accept the callback inside and handle the Promise chain internally
Or you expose a promise and handle the callback externally in the main scope.
Let's refactor it to just return a Promise and handle the callback outside:
function getFilteredDates(startDate, endDate) {
const dateSet = new Set();
return new Promise((resolve, reject) => {
const getAllDates = (isDone) => {
if (isDone) {
const Dates = Array.from(dateSet).join();
resolve(Dates);
return;
}
getTestedDates(startDate, endDate, region, func, memory,
lastDateKey, dateSet).then(getAllDates).catch((error) => {
reject(error);
});
};
lastDateKey = '';
getTestedDates(startDate, endDate, region, func, memory,
lastDateKey, dateSet).then(getAllDates).catch((error) => {
reject(error);
});
});
}
module.exports = getFilteredDates;
OK, figured it out, it was my bad. The inner function that called the callback with the status code didn't have a null when returning 200 (success) and that failed lambda over and over again. Anyway, I rewrote my lambda to be:
module.exports.getAvailableDates = (event, context, callback) => {
const lambdaParams = retrieveParametersFromEvent(event);
getFilteredDates(lambdaParams.startDate, lambdaParams.endDate)
.then(Dates => callback(null, { statusCode: 200, body: Dates}))
.catch(error => callback({ statusCode: 500, body: error}));
};
And now it works fine. Thanks for anyone who tried helping!
Oren