I have a class called Reel that has 2 functions. Inside one of them I'm defining a new promise and trying to access the other function from inside its callback. However the other function is undefined. Here's the relevant code:
class Reel {
constructor(reelContainer, idx, initialSymbols) {
// some code here
}
spin() {
const animationPromise = new Promise(resolve => this.animation.onfinish = resolve);
const timeoutPromise = new Promise(resolve => {
console.log('debug here...');
console.log(this);
console.log(this.fetchResults());
this.fetchResults().then(() => {
console.log('got results from the backend...');
resolve();
});
// setTimeout(resolve, this.regularGameFactor * 1000);
});
// som other code here
}
fetchResults() {
// some code here...
resolve();
}
}
I see that this has the value of instance of Reel, however this.fethResults() is undefined.
ok, if i have you understand correcly, you want basically to call
this.fethResults()
This can be done by declaring a variable and assign the reference "this" to this variable and then you can make the call inside the promise
var self = this; //outside of the promise
self.fethResults() //inside the promise
Related
I am looking at an implementation of a Promise class (at bottom). The constructor takes a function, f.
So if I have a regular function I want to pass in:
function myFunc() {
console.log("My Func");
}
If a Promise looks like this :
let promise = new Promise(resolve => {
myFunc();
}
then I am confused as to what f represents now though in the constructor of the class below. It appears as though resolve is the argument, not a function, f.
*Promise Class
class Promise {
constructor(f) {
this.onResolves = [];
this.status = "pending";
const resolve = value => {
debugger
this.status = "resolved";
this.value = value;
this.callOnResolves();
};
f(resolve);
}
callOnResolves() {
if (this.status === "resolved") {
this.onResolves.forEach(onResolve => onResolve(this.value));
this.onResolves.length = 0;
}
}
then(onResolve) {
return new Promise(resolve => {
this.onResolves.push(value => resolve(onResolve(value)));
this.callOnResolves();
});
}
}
f is the function that you pass to the promise's constructor. It takes a resolve parameter, which should eventually be called with the result of the asynchronous work.
Typically, your anonymous function would make use of an api that supports callbacks instead of promises, and in your callback to that api you would call resolve to let the Promise know that your asynchronous work is complete.
This is actually how you could implement an asynchronous sleep method using setTimeout.
function sleep(milliseconds) {
return new Promise(resolve => {
setTimeout(resolve, milliseconds);
});
}
sleep(1000).then(() => console.log(new Date()));
I have a series of promise functions that I'm chaining together. I don't need the specific result from the previous function so I'm not adding anything into resolve(); I just need them to run sequentially.
However, there is a variable in the containing scope that I want to pass into the first and fourth(last) promise. When I add it as a parameter to the third promise, the function runs immediately.
How can I pass a parameter into a chained promise and not call the function/promise at that time?
Here is the basics of what I'm trying to do:
const containingFunction = function() {
const varToPass = document.querySelector("#ID").value.trim();
firstPromise(varToPass)
.then(secondPromise)
.then(thirdPromise)
.then(fourthPromise(varToPass))
.catch(e =>{
console.error(e));
} );
};
FourthPromise:
const fourthPromise = function(varPassed) {
return new Promise(function(resolve, reject) {
do some stuff but only after the thirdPromise has been resolved
console.log(varPassed)
resolve();
});
};
You have two possibilities depending on how you want to resolve varToPass.
Lambda
Using a lambda function (anonymous function without own scope) as described by #Jaromanda X:
() => return fourthPromise(varToPass)
which will cause the function to keep a reference to the variable and not its value. The value of varToPass will be evaluated as soon as the fourthPromise is fired, not when this code is run.
Wrapper
The second option is using a wrapper, i.e. a function that returns a function:
function fourthPromise(varToPass) {
return function() {
return new Promise(function(resolve, reject) {
do some stuff but only after the thirdPromise has been resolved
console.log(varToPass)
resolve();
});
};
}
In this case the value of the passed variable is evaluated at the time this code runs and not when the callback is called.
Which option is better applicable to your case we can't tell without more context though.
Very simple change
const containingFunction = function() {
const varToPass = document.querySelector("#ID").value.trim();
firstPromise(varToPass)
.then(secondPromise)
.then(thirdPromise)
.then(() => fourthPromise(varToPass))
.catch(e =>{
console.error(e));
} );
};
I want to override the Promise constructor and the then method in Promise.
So, whenever someone creates a new Promise object, first my code will be executed and then the original promise constructor will get called.
Similarly, when someone calls .then function of Promise, first my code will get executed and then the callback of then function will get executed.
I tried this
var bind = Function.bind;
var unbind = bind.bind(bind);
function instantiate(constructor, args) {
return new (unbind(constructor, null).apply(null, args));
}
var oldProto = Promise.prototype;
Promise = function() {
console.log("Promise instantiated");
var promise = instantiate(Promise, arguments);
return promise;
};
Promise.prototype = oldProto;
While calling this using
var myFirstPromise = new Promise((resolve, reject) => {
setTimeout(function(){
resolve("Success!"); // Yay! Everything went well!
}, 250);
});
myFirstPromise.then((successMessage) => {
console.log("Yay! " + successMessage);
});
It led to infinite loop with console filled up with Promise instantiated log. I also tried the following:
Promise = function(Promise) {
MyPromise.prototype = Promise.prototype;
function MyPromise(){
console.log("Hello");
var promise = Function.prototype.bind.apply(MyPromise, arguments);
console.log(promise);
return promise;
}
}(Promise);
But, I am not sure whether the constructor overriden is the correct way to do it and how to define the then function for Promise.
I need a initialization function called only one time for a module. This function is a promise and is called by an execute function. If execute is called twice, the second must wait the initialization then continue the execution.
I wrote this code, but the second call of execute is always waiting and doesn't never return. What have i missed?
var initialized = false;
var initializing = false;
var initializationPromise;
var init = function () {
initializing = true;
return q.promise(function (resolve) {
// simulate initialization
setTimeout(function () {
// initialized
initialized = true;
resolve();
}, 1000);
}).fin(function () {
initializing = false;
});
};
var execute = function () {
return q.promise(function (resolve, reject, notify) {
if (initialized) {
// already initialized
resolve();
} else {
if (!initializing) {
// initializing
initializationPromise = init().then(function () {
// simulate execution
setTimeout(function () {
resolve();
}, 1000);
}, function (reason) {
reject(reason);
});
} else {
// Wait : initializing in progress
return initializationPromise;
}
}
});
};
execute().then(function () {
// This is executed
});
execute().then(function () {
// This is never executed
});
// Wait : initializing in progress
return initializationPromise;
is not correct. That doesn't wait for anything, it just drops out of the q.promise constructor and does not do anything. Also you seem to employ the Promise constructor antipattern.
What you should do instead is
var initialisationPromise = null;
function isInitialised() {
return initialisationPromise != null && initialisationPromise.isFulfilled();
}
function isInitialising() {
return initialisationPromise != null && initialisationPromise.isPending();
}
function init() {
// init can be called as often as necessary, and returns when it's done
if (initialisationPromise == null) { // do the test here!
// this part runs only once
initialisationPromise = q.promise(function (resolve) {
// simulate initialization
setTimeout(function () {
// initialized
resolve();
}, 1000);
});
}
return initialisationPromise;
}
function execute() {
return init().then(function () {
return q.promise(function(resolve, reject, notify) {
// simulate execution
setTimeout(function () {
resolve();
}, 1000);
});
});
}
A resolved/rejected promise will maintain its state (resolved or rejected state), so you can use it to run the initialization code only once. To do that, the init() function should return always the same promise and not create it every time.
For this reason, we create a deferred object (initializationDeferred) outside the init() method and use initializationDeferred to return the same promise every time init() method is called. We need, also, to check if the init() has been already done before, we use the shared variable initializationStarted to skip the setTimeout if already done in a previous invocation.
Now, inside execute you can be sure that the onFulfilled callback of then() is called only when init() method is initialized.
var initializationDeferred = Q.defer(); // Create here the deferred object so it's common to all init() invocations
var initializationStarted = false;
var init = function() {
if (!initializationStarted) {
initializationStarted = true;
setTimeout(function() {
// initialized
console.log('Init timeout fired!');
initializationDeferred.resolve(true); // Resolve the promise associated to the deferred object
}, 1000);
}
return initializationDeferred.promise; // Return the promise associated to the deferred object
};
var execute = function() {
return init().then(function(initialized) {
// Here your module is initialized and you can do whatever you want
// The value of "initialized" here is always "true"
console.log('Execute: initialized?', initialized);
});
};
execute().then(function() {
// This is executed
console.log('Execute First invocation');
});
execute().then(function() {
// This is executed too
console.log('Execute Second invocation');
});
<script src="http://cdnjs.cloudflare.com/ajax/libs/q.js/0.9.2/q.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)