How to translate Promise.try in coffeeScript - javascript

Hello I am looking for a code in coffe script which generates this code in javascript
Promise = require('bluebird');
myfunction = function(body) {
return Promise.try(function() {
return console.log('OK');
});
};
I have tried something like:
Promise = require 'bluebird'
myfunction: (body) ->
return Promise.try ->
return console.log('OK')
But the result is something like:
Promise["try"](function() {});
Any idea?? Thanks in advance

I would guess that something is off with the indentation in your file, as the above is correct except:
You don't need return, as the last statement in a function / block is automatically returned.
You should still use = for variable assignment, as opposed to : which is used for assigning properties when defining an object. It's the same in Coffeescript as in Javascript.
This code:
Promise = require 'bluebird'
myfunction = (body) ->
Promise.try ->
console.log 'OK'
Compiles just fine into:
var Promise, myfunction;
Promise = require('bluebird');
myfunction = function(body) {
return Promise["try"](function() {
return console.log('OK');
});
};

Regarding Promise.try -> transpiling into Promise["try"](function …) this is due to try being a reserved keyword in JS.

Related

How to assign variable to result of asynchronous class method that returns an object in its promise?

Looks nobody on internet describes similar problem, and similar solution is not working for me.
I am trying to scrape webpage so I created class for parser and one of the method looks like follows:
get chListUrl() {
return "http://www.teleman.pl/program-tv/stacje";
}
getChannels() {
var dict = {};
axios.get(this.chListUrl).then(function (response) {
var $ = cheerio.load(response.data);
var ile_jest_stacji = $('#stations-index a').length;
$('#stations-index a').each( (i,elem) => {
let href = $(elem).attr('href');
let kodstacji = href.replace(/\/program-tv\/stacje\//ig,'');
let nazwastacji = $(elem).text();
dict[nazwastacji]=kodstacji;
});
return dict;
}).catch(function (error) {
console.log(error);
return null;
}).finally(function() {
console.log("Koniec");
});
}
And problem is getChannels must be indirectly asynchronous because it contains axios BUT
let tm = new TM();
var a = tm.getChannels();
a is always undefined and it should be dictionary! Such construct means "assing to variable a result of execution of tm.getChannels()" so assignment should always be done AFTER whole function ends. Otherwise such syntax in language is useless because you will never be sure what value is stored in variable, and such errors are difficult to find and debug.
var a = await tm.getChannels();
NOT WORKING -> SyntaxError: await is only valid in async function (huh?)
adding async to getChannels() changes nothing.
Assing async to getChannels() and remove 'await' from assignment returns Promise{undefined} (huh?)
putting async before axios changes nothing as response is already handled by .then()
changing return dict to return await dict gives another "await is only valid in async function" (huh? axios is asynchronous)
I'm scratching my head over this for 2 weeks.
In Swift when something is return in completion handler it is assigned to variable in proper moment, why something returned by Promise not works the same way?
You need to be inside an async function to use the await expression:
The await operator is used to wait for a Promise. It can only be used inside an async function.
await operator on MDN
Example sourced from MDN:
async function f1() {
var x = await resolveAfter2Seconds(10);
console.log(x); // 10
}
f1();
Fixing your issue
class TM {
get chListUrl() {
return "http://www.teleman.pl/program-tv/stacje";
}
async getChannels() { // you need not use get syntax
let dict = {};
try { // we will be handling possible errors with try catch instead of reject
const response = await axios.get(this.chListUrl);
let $ = cheerio.load(response.data);
let ile_jest_stacji = $('#stations-index a').length;
$('#stations-index a').each( (i,elem) => {
let href = $(elem).attr('href');
let kodstacji = href.replace(/\/program-tv\/stacje\//ig,'');
let nazwastacji = $(elem).text();
dict[nazwastacji]=kodstacji;
});
return dict;
} catch(ex) {
console.log(ex);
return null
}
}
}
// let's make it work!
(async function() {
const tm = new TM()
const channels = await tm.getChannels()
// do whatever you want with channels
console.log(channels)
})()
Now, you're probably not going to call getChannels out of nowhere like this instead you will probably be inside a function that you yourself defined, you need to add the async keyword to this function. Whatever block function your code is in needs to be async.
If you want to use the async/await syntax you should remove the .then() syntax and you can resolve that way:
async getChannels() {
const response = await axios.get(this.chListUrl);
return response
}
You can learn more about async/await in the link: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

q- When to return like "defer.resolve(myData); return defer.promise;" VS simply "return myData" in promise chain

I've been trying to write better code on my node.js server and after reading some blog posts like the following:
http://www.codelord.net/2015/09/24/$q-dot-defer-youre-doing-it-wrong/ (angular specific but same concept)
http://bahmutov.calepin.co/linking-promises.html
I am still not sure if I'm returning my data down the promise chain the "right way".
I cannot tell when it's appropriate to return or pass data down a promise like this
case 1
var promise = function () {
var defer = q.defer();
var myData = "hi"
defer.resolve(myData);
return d.promise;
};
or like this.
case 2
var promise = function () {
var myData = "hi"
return myData;
};
I'm assuming is that if I know something will be returned where it's not possible for the promise chain to break then use case 2 but if their is a change it could fail (i.e. it's returning data from a network call but the user is offline) then use case 1 so it can handle both cases. Is that correct or do I have a misunderstanding about how this flow/process works.
In both cases you are returning a result which is instantly known or computed, while you are wrapping it in a promise in the first case. Whether or not you want to do this depends on whether it should be transparent for the caller of your function if the result is computed asynchronously or not. If you return a promise you are free to change the implementation of your function later to compute or retrieve the result asynchronously.
Two hints:
You are not using a promise in case 2 so don't call your function promise.
In the first case you can just return q("hi"); to wrap the literal in a promise.
promise is for those who engage callback hell, which means your jobs are Asynchronous and chained
for a simple case like $.ajax().success(callback1).fail(callback2) is type of promise
3.your case is not Asynchronous, it might be like this:
var promise1 = function() {
//async get file name
}
var promise2 = function(filename) {
var defer = q.defer();
var myData = "hi"
//async
fs.readFile(filename, 'utf-8', function(err, data) {
if (err) {
defer.reject(err);
} else {
defer.resolve(myData);
}
}
}
return d.promise;
};
var promise3 = function(data) {
//use data do something
}
var onError(err) {
console.log(err);
}
var onDone(result) {
console.log(result)
}
//your logic might look like
promise1.then(promise2).then(promise3).catch(onError).done(onDone);

How to return a value and a promise from a function at the same time?

I'm doing something like this
var command1;
var command2;
var fn = function(param) {
var deferred = Q.defer();
var command = spawn(..., [
... passing different arguments based on param ...
]);
...
command.stdout.on('data', function(data) {
if (/... if process started successfully .../.test(data)) {
deferred.resolve();
}
});
...
if (param === 'command1') {
command1 = command;
} else {
command2 = command;
}
return deferred.promise;
};
Q.all([
fn('command1'),
fn('command2')
]);
and later on I'm calling command1.kill() and command2.kill(). I thought about passing command to resolve, but then it may never be called. I could pass command to reject also, so that I could call kill there if something goes wrong, but that feels weird.
How do I return command and the promise as well to the caller in an idiomatic way? Without the conditional part in fn. What are the possibilities?
I also thought about ES6's deconstructing assignment feature, but consider the following
...
return [command, deferred.promise];
}
[command1, promiseCommand1] = fn('command1');
[command2, promiseCommand2] = fn('command2');
Q.all([
promise1,
promise2.then(Q.all([
promiseCommand1,
promiseCommand2
])
]);
but this fails (at least in my particular case, where the commands should wait until promise2 is resolved), because the processes are already on their way when I pass promiseCommand1 and promiseCommand2 to Q.all.
Not sure if I used the correct deconstructing assignment syntax.
Just popped into my mind
var command1;
var command2;
var fn = function(param, callback) {
var deferred = Q.defer();
var command = spawn(..., [...]);
...
callback(command);
return deferred.promise;
};
Q.all([
fn('command1', function(command) {
command1 = command;
}),
fn('command1', function(command) {
command2 = command;
})
]);
Any other way?
Update
Since yesterday I've figured out how could I might use a deconstructing assignment (still not sure on the syntax)
Q.all([
promise1,
promise2.then(function() {
[command1, promiseCommand1] = fn('command1');
[command2, promiseCommand2] = fn('command2');
return Q.all([
promiseCommand1,
promiseCommand2
]);
})
]);
this way the commands will only be executed after promise2 is resolved.
Solution
Based on the accepted answer and my previous update I came up with this
command.promise = deferred.promise;
return command;
};
Q.all([
promise1,
promise2.then(function() {
command1 = fn('command1');
command2 = fn('command2');
return Q.all([command1.promise, command2.promise]);
})
]);
Works and seems to be a concise solution for me. I don't want to rely on ES6 for the deconstructing assignment. Also, I don't think I can use the feature to assign one value to a variable declared outside of the scope and assign the other in the local scope concisely. Returning
return {
command: command,
promise: deferred.promise
};
is also a possible solution, but less concise.
Q.all([
promise1,
promise2.then(function() {
var result1 = fn('command1');
var result2 = fn('command2');
command1 = result1.command;
command2 = result2.command;
return Q.all([result1.promise, result2.promise]);
})
]);
Correction
In the comment section in the accepted answer I was advised to call reject in fn to prevent my code hang forever because of a pending promise. I've solved this with the following
command.promise = deferred.promise.timeout(...);
return command;
};
Using timeout will return the same promise, however if the promise is not resolved in given timeout value the promise will be rejected automatically.
You should end up with something useful by turning your "pass command to reject" on its head. In other words, reject in response to a kill() command.
The trouble, as you know, is that fn() should return a promise, and a promise doesn't naturally convey the corresponding command's .kill() method. However javascript allows the dynamic attachment of properties, including functions (as methods), to objects. Therefore adding a .kill() method is simple.
var fn = function(param) {
var deferred = Q.defer();
var command = spawn(..., [
... passing different arguments based on param ...
]);
...
command.stdout.on('data', function(data) {
if (/... if process started successfully .../.test(data)) {
deferred.resolve();
}
});
...
var promise = deferred.promise;
// Now monkey-patch the promise with a .kill() method that fronts for command.kill() AND rejects the Deferred.
promise.kill = function() {
command.kill();
deferred.reject(new Error('killed')); // for a more specific error message, augment 'killed' with something unique derived from `param`.
}
return promise;
};
var promise1 = fn('command1');
var promise2 = fn('command2');
Q.all([promise1, promise2]).spread(...).catch(...);
promise1.kill() or promise2.kill() will give rise to "killed" appearing as error.message in the catch handler.
The two kills can be called as appropriate, for example ...
if(...) {
promise1.kill();
}
if(...) {
promise2.kill();
}
Alternatively, the .kill() methods will also detach cleanly without needing to .bind(), for example :
doSomethingAsync(...).then(...).catch(promise1.kill);
doSomethingElseAsync(...).then(...).catch(promise2.kill);
Note that fn() will work for any number of calls without the need for outer vars command1, command2 etc.
You can return an array and then use promise.spread method.
https://github.com/kriskowal/q#combination
.then(function () {
return [command, promise];
})
.spread(function (command, promise) {
});

Passing an extra parameter in the middle of a Promise chain

I need to throw in a userID param in the middle of a promise chain(it is the only promise that needs it). All the promises should execute in a synchronous order.
SideNote- All the similar examples on stackoverflow are all a bit different- like using lambda functions(I use declared functions).So I'm still not quite sure.
var initialize = function(userID) {
var firstPromise = Module2.getFirstPromise();
firstPromise.then(getSecondPromise)
.then(getThirdPromise)
.then(getFourthPromise) //<----Fourth promise needs userID
.then(getFifthPromise)
.then(Utils.initializeComplete);
}
All the promises are functions that look like this:
var thirdPromise = function() {
return new Promise(function(resolve, reject) {
//fetch data
//On Return, Store it
resolve() //Nothing needed to passed down from this promise
});
});
}
I'm trying this, and it "works", but I'm not sure if that is how I am "suppose" to handle something like this. :)
var initialize = function(userID) {
var firstPromise = Module2.getFirstPromise();
firstPromise.then(getSecondPromise)
.then(getThirdPromise)
.then(function(){ return fourthPromise(userID)})
.then(getFourthPromise)
.then(Utils.initializeComplete);
}
Note: getFirstPromise is coming from a different module in my code. That shouldn't be important to the question though :)
Assuming that firstPromise is really a promise but secondPromise and so on are actually functions returning promises, then yes, what you've done is how you're supposed to do that. Here's a live example on Babel's REPL, which looks like this:
function doSomething(userID) {
getFirstPromise()
.then(getSecondPromise)
.then(getThirdPromise)
.then(() => getFourthPromise(userID))
// Or .then(function() { return getFourthPromise(userID); })
.then(getFifthPromise)
.catch(err => {
console.log("Error: " + err.message);
});
}
doSomething("foo");
function getFirstPromise() {
console.log("getFirstPromise called");
return new Promise(resolve => {
setTimeout(() => {
resolve("one");
}, 0);
});
}
// and then second, third, fourth (with user ID), and fifth
(If you don't use arrow functions, just replace them with the function form.)
Note the catch in the example above. Unless you have a really good reason not to, a promise chain should always have a .catch if you don't return the result.
Your solution is perfectly fine. It might be easier to understand with concrete signatures.
If your thirdPromise doesn't take anything and doesn't return anything its signature might be written (pseudocode assuming a -> b is a function from a to b) as _ -> Promise (_). If it returns some value a, it would be _ -> Promise (a). If it took something and returned something it might be a -> Promise (b)
So you can reason about your promise chains as about functions taking some value and returning some other value wrapped in a promise. However, your fourthPromise looks differently:
fourthPromise : UserId -> a -> Promise (b)
Which can be written as:
fourthPromise : UserId -> (a -> Promise (b))
It takes one parameter before becoming an actual promise you can chain. In a way, it's a template of a promise.
If you want the plain .then chain in the main function, try to write getFourthPromise as a factory function
function getSomethingByUserID(userId) {
return function() {
return new Promise(function(resolve) {
//your actual async job
resolve('a result');
});
};
}
Then you will get plan list of thens
var firstPromise = Module2.getFirstPromise()
.then(getSecondPromise)
.then(getSomethingByUserID(userId))
.then(Utils.initializeComplete);
Do not forget that if you missed to provide userId to getSomethingByUserID, it will not work.

Returning new Object from Service that uses $resource

I am working on making my existing code a bit better and I would like to have two objects for interacting with a RESTful API.
Previously, I used $http to get get the data and return the promise. I would then .then some actions to it. Then I would requery to get additional data and repeat it. So there were several nested $http queries. I would like to avoid that if possible.
I would like to have a service (or a factory) that I can use to configure various query parameters and another object for massaging and outputting the response.
Here is what I have so far:
var solr1 = angular.module('solr', ['ngResource']);
solr1.run(function(){
console.log("Module Loaded");
});
solr1.service('solrser', function($resource,solrresult) {
console.log("In Solrser")
this.serverurl = 'url';
this.res = $resource(this.serverurl);
this.query = function (p) {
this.res.get(p).$promise.then(function(d) {
return solrresult(d);
});
}
});
solr1.factory('solrresult',function() {
return function(a) {
this.data = a;
this.ready = 0;
console.log("In Factory")
this.getdocs = function() {
console.log("Getting Data")
console.log(this.data);
return this.data.docs; //this is line 9
}
return this;
}});
Controller looks like this:
app.controller('app1cont', ['$scope', 'solrser', 'solrresult', function($scope,solrser,solrresult){
console.log("Start");
var res = solrser.query({'q':'potato'});
console.log(res)
console.log(res.getdocs())
}]);
The output looks like this:
Module Loaded solr_module.js:5
In Solrser solr_module.js:9
Start main_controller.js:6
undefined main_controller.js:9
TypeError: Cannot read property 'getdocs' of undefined
at new <anonymous> (.........../main_controller.js:10:21)
at Object.e [as invoke] (https://code.angularjs.org/1.3.1/angular.min.js:36:365)
at F.instance (https://code.angularjs.org/1.3.1/angular.min.js:75:91)
at https://code.angularjs.org/1.3.1/angular.min.js:58:287
at s (https://code.angularjs.org/1.3.1/angular.min.js:7:408)
at G (https://code.angularjs.org/1.3.1/angular.min.js:58:270)
at g (https://code.angularjs.org/1.3.1/angular.min.js:51:172)
at g (https://code.angularjs.org/1.3.1/angular.min.js:51:189)
at https://code.angularjs.org/1.3.1/angular.min.js:50:280
at https://code.angularjs.org/1.3.1/angular.min.js:18:8 angular.js:11339
In Factory solr_module.js:25
So the factory gets created after the controller resumes execution. What am I doing wrong here?
You have a timing issue.
app.controller('app1cont', ['$scope', 'solrser', 'solrresult', function($scope,solrser,solrresult){
console.log("Start");
var res = solrser.query({'q':'potato'});
console.log(res)
console.log(res.getdocs())
}]);
When you call solrser.query() it runs async to get the data. So the res is not populated with any real value until after the promise returns inside the "solrser" service. You would need to do something more like:
solrser.query({'q':'potato'},function(res) {
console.log(res);
console.log(res.getdocs());
}); // could be done as a promise as well....
Separately, you also are doing something really strange when the response is called inside the solrser service.
this.query = function (p) {
this.res.get(p).$promise.then(function(d) {
return solrresult(d);
});
}
Calling return from within the promise handler is not going to do you very much. You need to either call a callback or resolve a deferred. Something like this would work better:
this.query = function (p,callback) {
this.res.get(p).$promise.then(function(d) {
callback(solrresult(d));
});
}
Or as a promise
this.query = function (p) {
var defer = $q.defer();
this.res.get(p).$promise.then(function(d) {
defer.resolve(solrresult(d));
});
return defer.promise;
}
Or you could just pass the get(p).$promise through, etc.
UPDATE:
Since this is an async action, there will always be a promise or callback. You have to do one of:
app.controller('app1cont', ['$scope', 'solrser', 'solrresult', function($scope,solrser,solrresult){
var res = solrser.query({'q':'potato'},function() {
res.getDocs();
});
}]);
Or just straight callback
app.controller('app1cont', ['$scope', 'solrser', 'solrresult', function($scope,solrser,solrresult){
solrser.query({'q':'potato'},function(res) {
res.getDocs();
});
}]);
I see missing semicolon
console.log("In Solrser")
shouldbe
console.log("In Solrser");
also missing semicolon here
console.log("Getting Data")
console.log("In Factory")
in controller you have missing semicolons too.
I think this is a reason why your code don't work.
To avoid bug like missing semicolon you can use JSHint plugin in your IDE

Categories

Resources