calling asyncwait from a callback - javascript

I have a nodejs library written using the async/await module. I try to consume it from a library which uses regular callbacks. Here is a sample code:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async (function() {
var resultA = await (Promise.promisify(bar));
return 111;
})
function bar(callback) {
setTimeout(callback, 2000)
}
function moo() {
var f = async.cps(foo)
f(function(err, res) {
console.log(res)
})
}
moo()
I expected console.log to print 111 but instead it prints:
{ _bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_progressHandler0: undefined,
_promise0: undefined,
_receiver0: undefined,
_settledValue: undefined }
btw if I inline the foo implementation in the "async.cps" line it works (but this is not an option since its an external library).
Any idea?

I've looked at the library your using, and by the look of it (there isn't much, and certainly no working samples), you're not using it correctly.
async(fn) will return a function that accepts some input values and upon execution will return a promise (Probably standard Promises/A+). Inside, it will call fn with the input parameters, and will resolve the returned promise when fn has returned.
async.cps(...) will return a function that accepts some input values and a node style callback function (function (err, res)) and upon execution will return a void (undefined). Inside, it will call fn with the input parameters, and will call the callback function when fn has returned with the appropriate values.
what your code does is create a function with async(fn), then pass this function to async.cps(..) as if you called async.cps(async(fn)), but that doesn't make any sense.
What you could do if you wanted to "convert" a promise to a node style callback function (unpromisifying!) using this library is this:
function moo() {
var f = async.cps(function() {
return await (foo())
})
f(function(err, res) {
console.log(res)
})
}

You double-asynced the foo function. Here are your options, depending on whether you can modify the declaration of foo or not:
Leave foo async, and create a function f that accepts a node-style callback using cps:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async(function() {
var resultA = await (Promise.promisify(bar));
return 111;
});
function bar(callback) {
setTimeout(callback, 1000);
}
function moo() {
var f = async.cps(function() {
return await(foo());
});
f(function(err, res) {
console.log(res);
});
}
moo();
Leave foo async, and use an async moo:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async(function() {
var resultA = await (Promise.promisify(bar));
return 111;
});
function bar(callback) {
setTimeout(callback, 1000);
}
var moo = async(function() {
try {
var res = await(foo());
console.log(res);
} catch (err) {
}
});
moo();
Make foo already cps at the declaration:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async.cps(function() {
var resultA = await (Promise.promisify(bar));
return 111;
});
function bar(callback) {
setTimeout(callback, 1000);
}
function moo() {
foo(function(err, res) {
console.log(res);
});
}
moo();

Related

waiting for JS async func to complete before running some sync code

I have an async function getDataItem that returns a promise and passes data to another function preparePhysicianSchemaData which builds a global object physicianDetailsObj out of the passed data as well as data fetched after calling yet another async function inside it for each row of data it was initially passed.
getDataItem(listID, itemID).then(preparePhysicianSchemaData)
Only after the global object variable physicianDetailsObj is fully populated, then I need to call another function called buildSEOSchemaBlock(), whose job is to parse physicianDetailsObj object and build the final object needed.
I would rather not use setTimeOut to try to time this:
setTimeout(function(){ return getListItem(listID, itemID).then(preparePhysicianSchemaData) }, 10);
setTimeout(function(){ return buildPhysicianSchemaBlock() }, 3000);
How can I chain the last function like this: getDataItem(listID, itemID).then(preparePhysicianSchemaData).then(buildPhysicianSchemaBlock) ensuring that the last function runs only after the global object variable physicianDetailsObj is fully populated?
var physicianDetailsObj = {};
function getListItem() {} //returns promise
function preparePhysicianSchemaData(item) {
var tempPhysicianDetailsObj = {};
var currentPhysicianItemId = item.get_id();
tempPhysicianDetailsObj = {
"name" : item.get_item("Title"),
"url" : item.get_item("SEOCanonicalHref").match('href="([^"]+)')[1]
};
var currentItemPhysicianTag= item.get_item("PhysicianItemTag").get_label();
getPhysicianLocationDetailsFromServiceLocations(currentItemPhysicianTag).then(function(slitems) {
console.log(slitems);
var slitemEnum = slitems.getEnumerator();
//first empty the object
Object.keys(physicianDetailsObj).forEach(k => delete physicianDetailsObj[k]);
while (slitemEnum.moveNext()) {
var slitem = slitemEnum.get_current();
physicianDetailsObj[currentPhysicianItemId + '-' + slitem.get_id()] = {
"name": tempPhysicianDetailsObj["name"],
"image": tempPhysicianDetailsObj["image"],
"url": tempPhysicianDetailsObj["url"],
"streetAddress": slitem.get_item("LocationAddress"),
"addressLocality": slitem.get_item("LocationLU_x003A_LocationCity").get_lookupValue()
}
}
});
}
function buildSEOSchemaBlock(){ } //process physicianDetailsObj
getPhysicianLocationDetailsFromServiceLocations is an async function which is called inside preparePhysicianSchemaData
If preparePhysicianSchemaData is synchronous then you don't need to await it, just perform the operation after it. Something like this:
getListItem(listID, itemID).then(function() {
preparePhysicianSchemaData();
buildPhysicianSchemaBlock();
});
Or if there are results you need from the Promise, something like:
getListItem(listID, itemID).then(function(result) {
preparePhysicianSchemaData(result);
buildPhysicianSchemaBlock();
});
If it's asynchronous then you can chain the Promises, something like:
getListItem(listID, itemID)
.then(function(result) { return preparePhysicianSchemaData(result); })
.then(function(newResult) { return buildPhysicianSchemaBlock(newResult); });
Basically each call to .then() passes the result of the previous Promise to the new asynchronous function, returning that function's Promise.
If you need to execute functions in strict order one after another, use async/await and Promises, have a look at this demo
// Use async
(async () => {
// Function 1
const fn1 = (val) => {
return new Promise((resolve, reject) => {
// Do some stuff here
val = val + 1;
// Resolve result.
// Can be resolved from any level
// of nested function!
function nested1() {
function nested2() {
resolve(val);
}
nested2();
}
nested1();
});
};
// Function 2
const fn2 = (val) => {
return new Promise((resolve, reject) => {
// Do some stuff here
val = val * 2;
// Resolve result
resolve(val);
});
};
// Function 3
const fn3 = (val) => {
return new Promise((resolve, reject) => {
// Do some stuff here
val = val + 1000;
// Resolve result
resolve(val);
});
};
// Async code
let val = 5;
val = await fn1(val); // Wait until fn1 resolves
val = await fn2(val); // Wait until fn2 resolves
val = await fn3(val); // Wait until fn3 resolves
console.log(val);
})();

Read Async Object Set Using Await

A global object has its key/value (thing) is set in an async function setter(); using await. How to asynchronously read the value of thing in another async function getter();?
I'm getting undefined error because the getter(); is running before the await in setter(); completes.
let obj = {};
async function af() {
return 1;
}
(async function setter () {
obj.thing = await af();
})();
(async function getter () {
let thing = obj.thing;
})();
You should wait for setter function to finish, you're getting a race condition problem with this approach.
An example of how that would work would be:
var obj = {};
async function af() {
return 1;
}
(async function() {
await (async function setter () {
obj.thing = await af();
})();
await (async function getter () {
let thing = obj.thing;
})();
console.log(obj.thing);
})();
At the end of the function it should log 1 that is returned on af function

Loop until all events are received in javascript

I have a function that waits for four external events (I have no control on them. They are randomly received)
function Foo() {
var this.data_1;
var this.data_2;
var this.data_3;
var this.data_4;
}
Foo.prototype.getData = function(){
deviceOne.on('data', (data) => {
this.data_1 = data;
});
deviceTwo.on('data', (data) => {
this.data_2 = data;
});
deviceThree.on('data', (data) => {
this.data_3 = data;
});
deviceFour.on('data', (data) => {
this.data_4 = data;
});
return {
"data_from_device_1": this.data_1,
"data_from_device_2": this.data_2,
"data_from_device_3": this.data_3,
"data_from_device_4": this.data_4
}
};
var foo = new Foo();
console.log(foo.getData()); // {'undefined', 'undefined', 'undefined', 'undefined'}
As you can see, the function won't wait for them and it will return 4 undefined objects. I've been looking for a solution and it seems like using async could help. It's just I didn't understand how to use it correctly in my case
To use async (and it does help here), first you need to do a promise version of your deviceXYZ.on:
const waitForData = device => new Promise((resolve, reject) => {
device.on('data', (data) => {
resolve(data);
});
// ...presumably hook up some kind of error event and use `reject` here...
});
Then (I've converted to class syntax here since if you're using async, you can use the new, simpler notation):
class Foo {
async getData() {
// ^^^^^
const data = await Promise.all([
// ^^^^^
waitForData(deviceOne),
waitForData(deviceTwo),
waitForData(deviceThree),
waitForData(deviceFour)
]);
this.data_1 = data[0];
this.data_2 = data[1];
this.data_3 = data[2];
this.data_4 = data[3];
return {
data_from_device_1: this.data_1,
data_from_device_2: this.data_2,
data_from_device_3: this.data_3,
data_from_device_4: this.data_4
};
}
}
Then code using it also has to be in an async function:
( async () => {
// ^^^^^
try {
const foo = new Foo();
console.log(await foo.getData()); // {'undefined', 'undefined', 'undefined', 'undefined'}
// ---------^
} catch (e) {
// Handle/report error
}
})();
...or it can use the promise directly in a non-async function:
const foo = new Foo();
foo.getData()
.then(result => {
console.log(result);
})
.catch(error => {
// Handle/report error
});
More:
async/await
Promise
Promise.all
class
Arrow functions
Side note: This is invalid syntax:
function Foo() {
var this.data_1; // Error here
var this.data_2;
var this.data_3;
var this.data_4;
}
At the moment, you don't declare properties in JavaScript. However, before too long (possibly ES2019, almost certainly ES2020) class syntax will be extended by the class fields proposal, currently at Stage 3 in the proposals process. When that happens, you can declare the "shape" of objects created by the Foo class (which can mean the objects go through fewer shape changes, which helps improve performance; it's also useful documentation for people reading the code). That would change Foo to look like this:
class Foo {
data_1; // These are field (property) declarations
data_2;
data_3;
data_4;
async getData() {
// ...
}
}

Javascript Kriskowal Q JS promise not working

I have created a promise using kriskowal/q module but when i try to use this it does not go into any function either happy path or error path.
here is my promise creation class
var Q = require('q');
var Test = function () {
};
Test.prototype = (function () {
var testt = function () {
var deferred = Q.defer();
var x = 5;
if (x === 5){
deferred.resolve('resolved');
}else{
deferred.error(new Error('error'));
}
return deferred.promise;
};
return {
testt : testt
}
}());
module.exports = Test;
and this is how i am going to use it
var Test = require('../src/js/test.js');
describe("Test", function () {
"use strict";
var test = null;
beforeEach(function () {
test = new Test();
});
it("should return the promise", function () {
test.testt().then(
function (a) {
console.log(a);
},
function (b) {
console.error(b);
}
);
});
});
since this is a jasmine test class if your not familiar with jasmine, what is inside 'it' function is the logic how i am using the promise. And the 'testt' is the function where i create the promise. for more clarification i have attached the entire code.
Issue : It does not print either a or b
Your it is finishing immediately, instead of after the promise's resolution/rejection.
it("should return the promise", function (done) {
test.testt().then(
function (a) {
console.log(a);
done();
},
function (b) {
console.error(b);
done();
}
);
});
See here for more info.

Javascript ES6 Generators

I'm diving into javascript generators and I'm really confused.
I'm using node#0.11.x to run this example:
function find() {
process.nextTick(function() {
it.next(1);
});
};
var it = (function* main() {
var k = yield find();
console.log(k);
})();
it.next();
Is there a way to grab the reference to next function inside the generator?
Something like:
function find(next) {
process.nextTick(function() {
next(1);
});
};
(function* main() {
var k = yield find(this.next);
console.log(k);
})().next();
To answer your question directly, you can't because this inside a generator function is not the generator instance, it is the context of the function call. You could do:
function find(next) {
process.nextTick(function() {
next(1);
});
};
var it = (function* main() {
var k = yield find(it.next.bind(it));
console.log(k);
})();
it.next();
but that's pretty hard to follow. Generally this would be accomplished with a coroutine library like co. With that, you would yield a promise, and when the promise is resolved, co will call .next with the value that the promise resolved with.
var co = require('co');
function find(){
return new Promise(function(resolve){
process.nextTick(function(){
resolve(1);
});
});
}
co(function * (){
var k = yield find();
console.log(k);
});

Categories

Resources