How to call to new object in promise join - javascript

I use the promise join and I need to use send the data from the readFile to myFacade (src) and my facade send obj to getA which latter on will be sent to arg[0]...
run = function (filePath) {
return Promise.join(
fs.readFileAsync(filePath, 'utf8')
.then(myFacade)
.then(getA),
users.getUsersAsync(usersObj)
.then(users.modifyRec.bind(null, process.env.us))
).then(function (args) {
return runProc('run', args[0], args[1]);
....
To make this work not in promise you should do something like
var parsed = new MyFacade(str);
var attribute = parsed.getA()
This is the code which should be called
var yaml = require('yamljs');
function MyFacade(src) {
this.data = yaml.parse(src);
}
MyFacade.prototype = {
getA: function () {
return this.data.def_types.web;
},
getB: function () {
return this.data.conars;
}
};
module.exports = MyFacade;
how to make it work with the promise chain above?

Just pass exactly the code you'd have used without promises as a callback:
return Promise.join(
fs.readFileAsync(filePath, 'utf8')
.then(function(str) {
var parsed = new MyFacade(str);
var attribute = parsed.getA()
return attribute;
}),
users.getUsersAsync(usersObj)
.then(users.modifyRec.bind(null, process.env.us)),
function(attr, rec) {
return runProc('run', attr, rec);
});

You're using
.then(getA)
Which means "call the function getA on the result of the previous promise." But you don't have a function getA; the result of the previous promise has a method getA. You want call:
.call('getA')
As for
.then(myFacade)
There are two options. One is a common thing to add to a constructor function:
function MyFacade(src) {
if(!(this instanceof MyFacade)) return new MyFacade(src);
this.data = yaml.parse(src);
}
This allows the constructor to be called without new. Alternatively, you can pass an anonymous function to then:
.then(function(str) {
return new MyFacade(str);
})

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

Wrapper function which returns promise irrespective of function arguments

In my project, I have a scenario where I have different kind of functions with different arguments. One of those arguments holds the callback function. And also there is a case where the function doesn't have any arguments. As shown below:
abc(string, function, number)
aaa(function, string)
bcd()
xyz(function)
cda(string, number, function, string)
I need to write a function such that irrespective of the irregularity of above functions, the function should return a promise.
Example:
// Assume $q has been injected
var defer = $q.defer();
function returnPromise(functionName, functionArgumentsInArray){
defer.resolve(window[functionName].apply(null, functionArgumentsInArray));
return defer.promise;
}
As you can see, the above function doesn't resolve the callback function but just the function.
Note: The functions will have max of one function argument or none.
I know it can be done individually for each case as follows:
function returnPromise(){
var defer = $q.defer();
abc("hey", function() {
defer.resolve(arguments);
}, 123);
return defer.promise;
}
But I am looking for a common wrapper for all such functions.
I think you are looking for something like
const cbPlaceholder = Symbol("placeholder for node callback");
function wrap(fn) {
return function(...args) {
return $q((resolve, reject) => {
function nodeback(err, result) {
if (err) reject(err);
else resolve(result);
}
for (var i=0; i<args.length; i++)
if (args[i] === cbPlaceholder) {
args[i] = nodeback;
break;
}
const res = fn.apply(this, args);
if (i == args.length) // not found
resolve(res);
});
};
}
You could use it as
const abcPromised = wrap(abc);
abcPromised("hey", cbPlaceholder, 123).then(…)
Also have a look at How do I convert an existing callback API to promises?. In general you should not need that placeholder thing when all promisified functions follow the convention to take the callback as their last parameter.

How can i store Promise instead of Deferred

I have a piece of code, which communicate with iOS native layer by dispatching request with callback ID, and storing Deferred in array. Then when the callback comes, we can resolve or reject this Deferred.
My code:
jsGate = (function () {
function jsGate() {}
jsGate._messageCount = 0;
jsGate._callbackDeferreds = {};
jsGate.dispatch = function (plugin, method, args) {
var callbackID, d, message;
callbackID = this._messageCount;
message = {
plugin: plugin,
method: method,
"arguments": args,
callbackID: callbackID
};
send(message)
this._messageCount++;
d = new Deferred;
this._callbackDeferreds[callbackID] = d;
return d.promise;
};
jsGate.callBack = function (callbackID, isSuccess, valueOrReason) {
var d;
d = this._callbackDeferreds[callbackID];
if (isSuccess) {
d.resolve(valueOrReason[0]);
} else {
d.reject(valueOrReason[0]);
}
return delete this._callbackDeferreds[callbackID];
};
return jsGate;
})();
Examples of usage:
jsGate.dispatch("ReadLater", "fetchSomething", []).then(function (value) {
return console.log(value);
});
return jsGate.dispatch("ReadLater", "asyncError", []).then(function (value) {
return console.log(value);
}, function (reason) {
return console.log("Failed: " + reason);
});
What's the best practice for that using A+ Promises?
After long research: there's no clean way of doing this without strange hacks. The main difference between Deferred and Promise is that we can't manipulate the Promise result from outside. In general - it's good approach, but in this specific case, we need that functionality, so - we have to stick with Deferred.

how can to execute multiple actions in one line?

In my case I have one repository like this from temphire (breeze)
define(['durandal/system'], function (system) {
var Repository = (function () {
var repository = function (entityManagerProvider, entityTypeName, resourceName, fetchStrategy) {
.........
this.find = function (predicate) {
var query = breeze.EntityQuery
.from(resourceName)
.where(predicate);
return executeQuery(query);
};
function executeQuery(query) {
return entityManagerProvider.manager()
.executeQuery(query.using(fetchStrategy || breeze.FetchStrategy.FromServer))
.then(function (data) { return data.results; });
}
................
};
return repository;
})();
return {
create: create,
getCtor: Repository
};
function create(entityManagerProvider, entityTypeName, resourceName, fetchStrategy) {
return new Repository(entityManagerProvider, entityTypeName, resourceName, fetchStrategy);
}
});
NOW
HOW CAN DO LIKE SOME THIS
repository.query(predicate).execute();
function query(predicate) {
return query = breeze.EntityQuery
.from(resourceName)
.where(predicate);
};
function executeQuery(query) {
return entityManagerProvider.manager().executeQuery(query.using(fetchStrategy || breeze.FetchStrategy.FromServer)).then(function(data) {
return data.results;
});
}
function execute() -- >
return executeQuery
the first action return query and after to execute
many thanks
I think the problem with what you are trying is that return terminates execution. If you want to do something as well as return in that function, then you need to do it before you return.
If, on the other hand, you really need to return the value and then execute something, then you should have the method that calls the function expecting the return, call the function to get the return value, and then have that calling function execute the thing you want executed. If that execution needs some data from the function that returns the value, then return that information with the value returned, and pass it into the function that does the execution.
Use
executeQueryLocally // This is syn
instead of
executeQuery // This is async
executeQuery sync

Strange behaviour in javascript Promise

Considering code snippet below,
function one(){
var prm = new Promise(function(resolve,reject){
});
prm.customKey = function(){
}
return prm;
}
function two(){
return one().then(function(){
//something
});
}
Now calling the function two, returns a promise in which 'customKey' is missing
function three(){
return one();
}
But while doing the same thing in function three(without handling success using 'then'),
returns a promise which has 'customKey' in it.
Can someone clarify me whats really happening and why?
As you can see from "Mozilla Docs" then method returns new Promise (e.g: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then).
If you want to assign a function to retrieve / do something in resolve function do it like this:
var prm = new Promise((resolve, reject) => {
let customKeyFunction = () => {
console.log("I'm custom key function.");
};
resolve(customKeyFunction);
})
From now on you can call this function like that:
function two() {
return one().then(customKey => {
customKey();
})
}

Categories

Resources