Can some one explain this to me ... have a global object and using some promises as below. When I reference the global in my function directly the reference is correct. When I try pass the reference it is not.
var globalObj = { ... }
function one() {
var deferred = Q.defer();
...
deferred.resolve();
...
return deferred.promise;
}
function two {
var deferred = Q.defer();
...
deferred.resolve();
...
return deferred.promise;
}
function doSomthing() {
var ref = globalObj; // this is ok
...
}
one().
.then(two)
.then(doSomething) // (1) this is ok it works
the alternative is ...
var globalObj = { ... }
function one() {
var deferred = Q.defer();
...
deferred.resolve();
...
return deferred.promise;
}
function two {
var deferred = Q.defer();
...
deferred.resolve();
...
return deferred.promise;
}
function doSomthing(someRef) {
var sref = someRef; // someRef is []
...
}
one().
.then(two)
.then(doSomethhing(globalObj)) // (2) this is not ok does not work
Note that there are two versions of code listedI tried (1) passing no reference and this was fine and (2) passing a reference and this was not. I am not sure if this is a scoping issue or an issue with Q. Any ideas ?
This
one()
.then(two)
.then(doSomething(globalObj));
should be
one()
.then(two)
.then(function () {
return doSomethhing(globalObj);
});
because you don't want to call doSomething() immediately, but that's exactly what the first variant does.
Related
I have put up a small example of my use case, see below (jsfiddle: https://jsfiddle.net/BWNba/165/):
Basically Q.all would only work correctly when the biggest job is processed first. Is there anything I am doing here to get this to work correctly ?
function findPersonWithId(id) {
var deffered = Q.defer();
setTimeout(function(){
var newPerson = {id: 123}
deffered.resolve(newPerson)
},300)
return deffered.promise;
}
function loadHobbies(person) {
var deffered = Q.defer();
setTimeout(function(){
person.hobbies = ['programming', 'surfing', 'cooking']
deffered.resolve(person)
},100)
return deffered.promise;
}
function loadAddress(person) {
var deffered = Q.defer();
setTimeout(function(){
person.address = 'Melbourne, Australia'
deffered.resolve(person)
},200)
return deffered.promise;
}
function loadPersonalDetails(person) {
var deffered = Q.defer();
setTimeout(function(){
person.name = 'Bob'
person.age = 99
person.gender = 'male'
deffered.resolve(person)
},300)
return deffered.promise;
}
function loadRand(person) {
var deffered = Q.defer();
var rand = ~~(Math.random() * 1000)
setTimeout(function(){
person[rand] = rand
deffered.resolve(person)
},rand)
return deffered.promise;
}
function getPersonChain() {
return findPersonWithId(123)
.then(loadHobbies)
.then(loadAddress)
.then(loadPersonalDetails)
}
function getPersonQAllSmFirst() {
return findPersonWithId(123)
.then(function(person){
return Q.all(
loadHobbies(person),
loadAddress(person),
loadPersonalDetails(person)
)
})
}
function getPersonQAllLgFirst() {
return findPersonWithId(123)
.then(function(person){
return Q.all(
loadPersonalDetails(person),
loadHobbies(person),
loadAddress(person)
)
})
}
getPersonChain()
.done(function(person){
$('.person').append(JSON.stringify(person))
})
getPersonQAllSmFirst()
.done(function(person){
$('.person2').append(JSON.stringify(person))
})
getPersonQAllLgFirst()
.done(function(person){
$('.person3').append(JSON.stringify(person))
})
Q.all accepts an array of promises and returns Promise which is resolved if all promises are resolved or rejected if one of them is rejected.
Your calls to Q.all(promise, promise, promise) are not valid. It has to be Q.all([promise, promise, promise]).
Returned promise is resolved with an array of results from promises, in your case it will be 3 same persons.
Little example (will print 1, 2, 3 to console):
Q.all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
]).then(function(numbers) { console.log(numbers); };
To make it work, you need to change your code like this https://jsfiddle.net/g8sgqrof/
var Q = require("q");
function test(v){
var deferred = Q.defer()
if (v) {
console.log("success");
deferred.resolve();
}
else{
console.log("failed");
deferred.reject(new Error("failed"))
}
return deferred.promise;
}
var over = function(url){
console.log("hahaha")
console.log(url)
}
var failed = function(){
console.log("wuwuw")
}
test().then(over, failed)
test().then(over("localhost"), failed)
When test().then(over, failed), function over should not execute,The program can do well,
I can get the result:
failed
wuwuw
But when I add params for function over, the function over will execute. I will get:
failed
hahaha
localhost
wuwuw
Obviously, I don't want the function over execute, but I need it get the params when test() resolved.
But when I add params for function over, the function over will execute.
That's because you're calling it. You still need to pass a function to then:
test().then(function(testResult) {
over("localhost");
}, failed)
I was wondering what the best approach is for configuring a module export. "async.function" in the example below could be a FS or HTTP request, simplified for the sake of the example:
Here's example code (asynmodule.js):
var foo = "bar"
async.function(function(response) {
foo = "foobar";
// module.exports = foo; // having the export here breaks the app: foo is always undefined.
});
// having the export here results in working code, but without the variable being set.
module.exports = foo;
How can I export the module only once the async callback has been executed?
edit
a quick note on my actual use-case: I'm writing a module to configure nconf (https://github.com/flatiron/nconf) in an fs.exists() callback (i.e. it will parse a config file and set up nconf).
Your export can't work because it is outside the function while the foodeclaration is inside. But if you put the export inside, when you use your module you can't be sure the export was defined.
The best way to work with an ansync system is to use callback. You need to export a callback assignation method to get the callback, and call it on the async execution.
Example:
var foo, callback;
async.function(function(response) {
foo = "foobar";
if( typeof callback == 'function' ){
callback(foo);
}
});
module.exports = function(cb){
if(typeof foo != 'undefined'){
cb(foo); // If foo is already define, I don't wait.
} else {
callback = cb;
}
}
Here async.function is just a placeholder to symbolise an async call.
In main
var fooMod = require('./foo.js');
fooMod(function(foo){
//Here code using foo;
});
Multiple callback way
If your module need to be called more than once you need to manage an array of callback:
var foo, callbackList = [];
async.function(function(response) {
foo = "foobar";
// You can use all other form of array walk.
for(var i = 0; i < callbackList.length; i++){
callbackList[i](foo)
}
});
module.exports = function(cb){
if(typeof foo != 'undefined'){
cb(foo); // If foo is already define, I don't wait.
} else {
callback.push(cb);
}
}
Here async.function is just a placeholder to symbolise an async call.
In main
var fooMod = require('./foo.js');
fooMod(function(foo){
//Here code using foo;
});
Promise way
You can also use Promise to solve that. This method support multiple call by the design of the Promise:
var foo, callback;
module.exports = new Promise(function(resolve, reject){
async.function(function(response) {
foo = "foobar"
resolve(foo);
});
});
Here async.function is just a placeholder to symbolise an async call.
In main
var fooMod = require('./foo.js').then(function(foo){
//Here code using foo;
});
See Promise documentation
An ES7 approach would be an immediatly invoked async function in module.exports :
module.exports = (async function(){
//some async initiallizers
//e.g. await the db module that has the same structure like this
var db = await require("./db");
var foo = "bar";
//resolve the export promise
return {
foo
};
})()
This can be required with await later:
(async function(){
var foo = await require("./theuppercode");
console.log(foo);
})();
ES6 answer using promises:
const asyncFunc = () => {
return new Promise((resolve, reject) => {
// Where someAsyncFunction takes a callback, i.e. api call
someAsyncFunction(data => {
resolve(data)
})
})
}
export default asyncFunc
...
import asyncFunc from './asyncFunc'
asyncFunc().then(data => { console.log(data) })
Or you could return the Promise itself directly:
const p = new Promise(...)
export default p
...
import p from './asyncModule'
p.then(...)
Another approach would be wrapping the variable inside an object.
var Wrapper = function(){
this.foo = "bar";
this.init();
};
Wrapper.prototype.init = function(){
var wrapper = this;
async.function(function(response) {
wrapper.foo = "foobar";
});
}
module.exports = new Wrapper();
If the initializer has error, at least you still get the uninitialized value instead of hanging callback.
You can also make use of Promises:
some-async-module.js
module.exports = new Promise((resolve, reject) => {
setTimeout(resolve.bind(null, 'someValueToBeReturned'), 2000);
});
main.js
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// outputs 'someValueToBeReturned' after 2 seconds
The same can happen in a different module and will also resolve as expected:
in-some-other-module.js
var asyncModule = require('./some-async-module');
asyncModule.then(promisedResult => console.log(promisedResult));
// also outputs 'someValueToBeReturned' after 2 seconds
Note that the promise object is created once then it's cached by node. Each require('./some-async-module') will return the same object instance (promise instance in this case).
Other answers seemed to be partial answers and didn't work for me. This seems to be somewhat complete:
some-module.js
var Wrapper = function(){
this.callbacks = [];
this.foo = null;
this.init();
};
Wrapper.prototype.init = function(){
var wrapper = this;
async.function(function(response) {
wrapper.foo = "foobar";
this.callbacks.forEach(function(callback){
callback(null, wrapper.foo);
});
});
}
Wrapper.prototype.get = function(cb) {
if(typeof cb !== 'function') {
return this.connection; // this could be null so probably just throw
}
if(this.foo) {
return cb(null, this.foo);
}
this.callbacks.push(cb);
}
module.exports = new Wrapper();
main.js
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined
});
main2.js
var wrapper = require('./some-module');
wrapper.get(function(foo){
// foo will always be defined in another script
});
I have this async function that I want to turn into a promise
var myAsyncFunction = function(err, result) {
if (err)
console.log("We got an error");
console.log("Success");
};
myAsyncFunction().then(function () { console.log("promise is working"); });
and I get TypeError: Cannot call method 'then' of undefined.
What is wrong with this code?
There are various ways in Q:
Q.nfcall(myAsyncFunction, arg1, arg2);
Q.nfapply(myAsyncFunction, [arg1, arg2]);
// Work with rusable wrapper
var myAsyncPromiseFunction = Q.denodeify(myAsyncFunction);
myAsyncPromiseFunction(arg1, arg2);
in Deferred implementation:
var myAsyncPromiseFunction = deferred.promisify(myAsyncFunction);
myAsyncPromiseFunction(arg1, arg2);
One notable difference: Wrappers as generated by Deferred additionally auto-resolve promises passed as an arguments, so you can do:
var readFile = deferred.promisify(fs.readFile);
var writeFile = deferred.promisify(fs.writeFile);
// Copy file
writeFile('filename.copy.txt', readFile('filename.txt'));
myAsyncFunction return nothing(undefined actually) in your code.
If you use whenjs, the normal way will be like this:
var myAsyncFunction = function() {
var d = when.defer();
//!!!do something to get the err and result
if (err)
d.reject(err);
else
d.resolve.(result);
//return a promise, so you can call .then
return d.promise;
};
Now you can call:
myAsyncFunction().then(function(result(){}, function(err){});
I have a flag , named 'flag', and when this flag get's a specific value , I want to invoke a specific function.
anyone knows how to do that?
var EventEmitter = require("events").EventEmitter;
var flags = Object.create(EventEmitter.prototype);
Object.defineProperty(flags, "someFlag", {
get: function () {
return this._someFlag;
},
set: function (v) {
this._someFlag = v;
this.emit("someFlag", v);
}
});
flags.on("someFlag", callback);