var dataPromise= $q.defer();
function getDataPromise(){
return dataPromise.promise;
}
(function getData(){
setTimeOut(
function(){
myPromise.resolve("data");
}
,1000);
})();
getDataPromise().then(function(){alert("use old data");});
In this code "dataPromise" defined out of "getData" function scope, therefor new promise won't be created on each "getData" invocation.
"getData" will invoce once and "dataPromise" will hold the first invoke data, and won't be update.
I want to understand if this is promise anty-pattern? if so - what is the correct way to call async function once?
Here's how I would write it:
const dataPromise = $q(function(resolve) {
setTimeOut(function() {
resolve("data");
}, 1000);
});
function getDataPromise() {
return dataPromise;
}
getDataPromise().then(function(){alert("use old data");});
Related
I'm studying promises; can anybody explain me why this piece of code does not work is I call the
function add() inside the resolve?
<script>
async function f() {
function add() {
return 14+3;
}
let promise = new Promise((resolve, reject) => {
setTimeout(()=>{resolve(add)}, 3000); //this doesn't work
setTimeout(()=>{resolve(14+3)}, 3000); // this works
});
let result = await promise;
alert(result);
alert ("END");
}
f();
</script>
When you resolve with value you actually returning value from promise. In your example you resolve with function in arguments, so your promise returns function(function add)
So modify line,
resolve(add);
to
resolve(add());
In the Master.aspx I have some init code
app.asynInit(
getData();// this needs to execute first
)
And then in one of the custom control I have some logic
doSomethingLater() // this needs to wait for the getData()
I am not sure what is the best way to make sure doSomething() always execute after app.asynInit()
My current solution is to use jQuery's custom event.
app.asynInit() // this needs to execute first
$(document).trigger('initCompleted')
$(document).on('initCompleted',function(){ document() // this needs to wait for the getData()})
It appears to work. But is there any better alternatives? Should I use document here?
You can try to use Promise class:
var initAsync = function () {
var promise = new Promise(function (done) {
setTimeout(function () {
console.log('DONE');
done();
}, 3000);
});
return promise;
};
(async function () {
await initAsync();
console.log('continue...');
// doSomething();
}());
Source: Promise
If you're using this action on IE old version. You can use callback function:
var init = function (callback) {
setTimeout(function () {
console.log('DONE');
callback();
}, 3000);
};
init(function () {
console.log('continue...');
// doSomething();
});
I end up in with this implementation with the callback approach:
In Master.aspx:
app.asynInit(
getData();// this needs to execute first
window.isDataGet = true;
)
function onDataGet(cb){
if(window.isDataGet )
cb();
else
setTimeout(onDataGet,100)
}
In Custom Control:
onDataGet(//callback function here)
$.when(fetchingOutcomeTab()).done(alert("1"));
function fetchingOutcomeTab() {
var dfd = $.Deferred();
setTimeout(function() {
dfd.resolve('qqqqq');
}, 2000);
return dfd.promise();
}
I am trying to make alert("1") triggered waiting until fetchingOutcomeTab function done, but everytime it will triggered immedietely, please help.
You need to pass a function to .done(). You're calling alert() immediately and passing its return value.
$.when(fetchingOutcomeTab()).done(() => alert("1"));
Since your function returns a deferred object, you can chain done() directly to the function call. Also, done() expects a parameter that's a "function or array of functions".
fetchingOutcomeTab().done(function() {
console.log('resolved.');
});
function fetchingOutcomeTab() {
console.log('Deferring...');
var dfd = $.Deferred();
setTimeout(function() {
dfd.resolve('qqqqq');
}, 2000);
return dfd;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You have a prototype object Foo with two async method calls, bar and baz.
var bob = new Foo()
Foo.prototype.bar = function land(callback) {
setTimeout(function() {
callback()
console.log('bar');
}, 3000);
};
Foo.prototype.baz = function land(callback) {
setTimeout(function() {
callback()
console.log('baz');
}, 3000);
};
We want to do bob.bar().baz() and have it log "bar" and "baz" sequentially.
If you cannot modify the method calls (including passing in your callback function), how can you pass a default callback into these method calls?
Some ideas:
Wrap "bob" with decorator (still fuzzy on how to implement, could use a small example)
Modify constructor to assign default callback if none assigned (have not considered if this is possible or not)
Use a generator wrapper that will continue to call next method until none are left?
The more recommended way instead is to use promises as this is the community-wide practice to do async work.
We want to do bob.bar().baz() and have it log "bar" and "baz"
sequentially.
Why would you want to do that just to achieve this bob.bar().baz() "syntax"? You could do it pretty neatly using the Promise API w/o additional efforts to make that syntax work that indeed increases code complexity reducing the actual readability.
So, you might want to consider using the promise-based approach like this. It offers much flexibility than what you would have achieved with your approach:
Foo.prototype.bar = function () {
return new Promise(function (resolve) {
setTimeout(function () {
resolve()
console.log('bar');
}, 3000);
};
};
Foo.prototype.baz = function () {
return new Promise(function (resolve) {
setTimeout(function () {
resolve()
console.log('baz');
}, 3000);
};
};
Now you'd do this to run them sequentially one after another:
var bob = new Foo();
bob.bar().then(function() {
return bob.baz();
});
// If you're using ES2015+ you could even do:
bob.bar().then(() => bob.baz());
If you need to chain more functions you could simply do it:
bob.bar()
.then(() => bob.baz())
.then(() => bob.anotherBaz())
.then(() => bob.somethingElse());
Anyway, if you're not used to using promises you might want to read this
Warning this isn't quite right yet. Ideally we'd subclass Promise and have proper then/catch functionality but there are some caveats with subclassing bluebird Promise. The idea is to store an internal array of promise generating functions, then when a Promise is waited on (then/await) serially wait on those promises.
const Promise = require('bluebird');
class Foo {
constructor() {
this.queue = [];
}
// promise generating function simply returns called pGen
pFunc(i,pGen) {
return pGen();
}
bar() {
const _bar = () => {
return new Promise( (resolve,reject) => {
setTimeout( () => {
console.log('bar',Date.now());
resolve();
},Math.random()*1000);
})
}
this.queue.push(_bar);
return this;
}
baz() {
const _baz = () => {
return new Promise( (resolve,reject) => {
setTimeout( () => {
console.log('baz',Date.now());
resolve();
},Math.random()*1000);
})
}
this.queue.push(_baz);
return this;
}
then(func) {
return Promise.reduce(this.queue, this.pFunc, 0).then(func);
}
}
const foo = new Foo();
foo.bar().baz().then( () => {
console.log('done')
})
result:
messel#messels-MBP:~/Desktop/Dropbox/code/js/async-chain$ node index.js
bar 1492082650917
baz 1492082651511
done
If you want to avoid callback hell and keep your sanity ES6 promises are the most appropriate approach for the sake of functional programming. You just chain up your sequential asynchronous tasks in the asynchronous timeline just like working in a synchronous timeline.
In this particular case you just need to promisify your asynchronous functions. Assume that your asynch functions takes a data and a callback like asynch(data,myCallback). Let us assume that the callback is error first type.
Such as;
var myCallback = (error,result) => error ? doErrorAction(error)
: doNormalAction(result)
When your asynch function is promisified, you will actually be returned a function which takes your data and returns a promise. You are expected to apply myCallback at the then stage. The return value of myCallback will then be passed to the next stage at where you can invoke another asynch function supplied with the return value of myCallback and this goes on and on as long as you need. So let's see how we shall implement this abstract to your workflow.
function Foo(){}
function promisify(fun){
return (data) => new Promise((resolve,reject) => fun(data, (err,res) => err ? reject(err) : resolve(res)));
}
function myCallback(val) {
console.log("hey..! i've got this:",val);
return val;
}
var bob = new Foo();
Foo.prototype.bar = function land(value, callback) {
setTimeout(function() {
callback(false,value*2); // no error returned but value doubled and supplied to callback
console.log('bar');
}, 1000);
};
Foo.prototype.baz = function land(value, callback) {
setTimeout(function() {
callback(false,value*2); // no error returned but value doubled and supplied to callback
console.log('baz');
}, 1000);
};
Foo.prototype.bar = promisify(Foo.prototype.bar);
Foo.prototype.baz = promisify(Foo.prototype.baz);
bob.bar(1)
.then(myCallback)
.then(bob.baz)
.then(myCallback)
I need to do this: browser have to make N requests to the server, requests mustn't be async, next requests are starting after previous requests will stop.
I can write some function A with for i < N i++ and calling this function A again recursively to do this, but it is not beautifull at all. Also, this called callback hell. I want some more beautifull solution.
I found deffered objects. Some says, it can help me to escape callback hell. I want something like this. setTimeout there is imitate one async request:
function foo1(some) {
debugger;
setTimeout(function foo1async() {
debugger;
deffered.resolve();
}, 500);
return deffered.promise;
}
function foo2(some) {
debugger;
setTimeout(function foo2async() {
debugger;
deffered.reject();
}, 500);
return deffered.promise;
}
function foo3() {
debugger;
setTimeout(function foo3async() {
debugger;
deffered.resolve();
}, 500);
return deffered.promise;
}
var deffered;
function doChain() {
debugger;
deffered = $q.defer();
var promise = deffered.promise;
promise.then(foo1);
promise.then(foo2);
promise.then(foo3);
promise["finally"](function () {
debugger;
});
deffered.resolve();
}
I expect foo1 to be called, then foo1async will be called and resolve deffered object.
foo2 must be called, then foo2async is called.
3.Now I expect, that foo3 wouldn't start, because deffered is rejected in foo2async. After that I expect foo in finally section called.
Actually, I have this:
foo1, foo2 and foo3 are called. Then foo in finally section called. Then foo1async, foo2async and foo3async funtions are called.
How I can get what I am expecting?
Actually, I will have something like this:
for(var i = 0; i < N; i++) {
(function (iter) {
promise.then(function () {
foo(iter);
});
})(i);
}
You got a few things wrong here.
First, you use a deferred to convert a callback-based async function into a promise-based - but each one needs its own deferred.promise and thus its own deferred. Actually, I prefer to use the $q constructor instead:
function fooN(input){
return $q(function(resolve, reject){
setTimeout(function(){
resolve(input + "; some more data");
}, 500);
});
}
(you could use var deferred = $q.defer() as well)
fooN now returns a promise, so you don't need to use $q.defer() anymore.
In fact, if the async function already was promise-based, like $timeout or $http, then you wouldn't have needed a deferred at all, for ex:
function fooN(input){
return $timeout(function(){
return input + "; some more data";
}, 500);
})
So, let's assume that foo1, foo2 and foo3 are implemented like fooN - all returning promises.
To make the calls sequential, you would need to chain promises - not to attach multiple handlers to the some root promise.
I'll break it down for you:
function doChain(){
var foo1Promise = foo1();
var foo2AfterFoo1Promise = foo1Promise.then(foo2);
var foo3AfterFoo2Promise = foo2AfterFoo1Promise.then(foo3);
var promise = foo3AfterFoo2Promise.then(function(finalData){
return doSomeProcessing(finalData); // if needed
});
promise.catch(function(error){
// "rethrow", if can't handle
return $q.reject({msg: "Some error occurred"});
})
return promise;
}
Or, the same, more concise:
function doChain(p){
return foo1(p)
.then(foo2)
.then(foo3)
.then(function(finalData){
return doSomeProcessing(finalData);
})
.catch(function(error){
return $q.reject({msg: "Some error occurred"});
});
}
A "promised" return value of each function is an input to the next chained function.
You can use $q.all method. For instance:
var promises = [promise1, promise2, ...];
$q.all(promises).then(function () {
// do something
});
What happens now is that all foo* promises depend on the single promise; when it gets resolved all are triggered. In ASCII art the dependencies are:
┎ foo1
promise ╁ foo2
┖ foo3
What you want is:
function doChain() {
foo1()
.then(foo2)
.then(foo3)
;
}
No need for the extra promise. No callback hell either!