I am trying to understand the difference between the 3 options:
.then(myCallback)
.then(myCallback())
.then(() => { myCallback() })
The myCallback function returns nothing and is used only for its side effects, so I don't need it to pass anything back to the promise chain. What I don't understand is why in my code only the second option triggers the function, when it seems like all the 3 should.
UPDATE: Here is the code with the bare essentials
serverCall(url, data) // fetch function
.then((response) => response.json())
.then(myCallback) // not running, only when () added
.catch((error) => { console.log(error) })
const myCallback = () => {
anotherServerCall(...).then(...)
}
UPDATE 2
After some digging I see that having .then((response) => response.json()) as the first then response is what is preventing .then(myCallback) to execute. Still no idea why...
All three should trigger the function, but the order differs between the approaches. If you're sometimes seeing evidence that the serverCall or myCallback aren't being invoked, then that has something to do with the particulars of those functions, not the ways you are calling them.
To demonstrate, consider two proxies for serverCall and myCallback that we know will always work. Let's apply each idea in your question to those:
This is the "normal" way to use then. Pass it a function that is invoked after the promise to which it is attached...
function serverCall() {
console.log('began server call');
return new Promise(function(resolve) {
setTimeout(() => {
console.log('completed server call');
resolve();
}, 2);
});
}
function myCallback() {
console.log('callback called');
}
serverCall().then(myCallback).then(() => console.log('done'));
// produces:
// began server call
// completed server call
// callback called
// done
Your first and third ideas are almost the same. Pass then a function which is invoked after the promise. In your third idea, the function isn't the callback, it's a function that calls the callback. One more stack frame, but the exact same effect...
function serverCall() {
console.log('began server call');
return new Promise(function(resolve) {
setTimeout(() => {
console.log('completed server call');
resolve();
}, 2);
});
}
function myCallback() {
console.log('callback called');
}
serverCall().then(() => { myCallback() }).then(() => console.log('done'))
// produces:
// began server call
// completed server call
// callback called
// done
Your second idea, as a commenter points out, invokes the function and passes it's result to then. The chaining of the then runs synchronously after starting the promise, so the results appear reordered: myCallback runs before the promise completes...
function serverCall() {
console.log('began server call');
return new Promise(function(resolve) {
setTimeout(() => {
console.log('completed server call');
resolve();
}, 2);
});
}
function myCallback() {
console.log('callback called');
}
serverCall().then(myCallback()).then(() => console.log('done'))
// produces:
// began server call
// callback called <------ CHANGED!!!
// completed server call
// done
The only way I've found to duplicate your problem is if the callback returns a function. Options 1 and 3 don't do anything because the returned function isn't being called. Option 2 is called and is successful.
function fetch() {
return new Promise((resolve, reject) => {
resolve();
});
}
function myCallBack() {
return function () {
console.log('Success');
};
}
fetch().then(myCallBack); // nothing
fetch().then(myCallBack()); // Success
fetch().then(() => myCallBack()); // nothing
Your use cases are different because
The first one then call, you are passing a callback to be invoked when then it’s executed, passing a naming function will appear in the stack trace if some error occurred
The second one, execute the callback passed before being passed to the then function and the result of that execution callback will be passing to the then function, so imagine this.
function myCallback(){
return function theRealCallbackPassed(thenResponse){
// do something with then response
}
}
The last one, will define an anonymous arrow function , so what is the diff between
then( () => {} )
And
then( function(){} )
The different is that using arrow function () => {} you have a short syntax and you are binded the function contexto to the current context where the arrow function it’s declared.
While the function() {} syntax is not shorter and it is not auto bindable.
Hope it can help you.
I have the following files:-
target.js
var target = function(repository, logger) {
return {
addTarget : function(target) {
repository.add(target).then(
function (newTarget) {
console.log("added");
logger.info("added");
},
function (err) {
console.log("error");
logger.info("error");
}
);
}
};
};
module.exports = target;
targetTest.js
var chai = require("chai"),
expect = chai.expect,
sinon = require("sinon"),
Promise = require("bluebird"),
baseTarget = require("../target");
describe("target", function(){
it("should log error when it occurs", function() {
var mockRepository = {
add : sinon.stub().returns(Promise.reject(new Error()))
};
var mockLogger = {
info : sinon.spy()
};
var target = baseTarget(mockRepository, mockLogger);
target.addTarget("target");
expect(mockLogger.info.calledWith("error")).to.be.true;
});
});
The issue I have is that expect(mockLogger.info.calledWith("error")).to.be.true; returns false because add method on the repository is async and so hasn't executed yet. Is there a pattern for doing this properly.
This is really more of a question about 'how Promises work' than how they work within test frameworks - the answer to which is that their behaviour remains exactly the same.
Is there a pattern for doing this properly.
It is not so much a pattern as it is what Promises are built to do. Each success handler of a then is executed in sequence on success of the last. In your code we can return the Promise created by calling repository#add as you would if you wanted to use its result or perform some external dependent operation outside of addTarget:
addTarget: function (target) {
return repository
// ^^^^^^
.add(target)
.then(function (newTarget) {
console.log("added");
logger.info("added");
}, function (err) {
console.log("error");
logger.info("error");
});
}
Then place your expectation inside a then that will be executed on success of all members of the Promise chain created in addTarget:
target.addTarget("target").then(function () {
expect(mockLogger.info.calledWith("error")).to.be.true;
cb();
});
Asynchronous Tests
You will notice in the example above that there is also a call to a function cb. Due to your test being asynchronous you need to 'tell' the test framework when the test has completed. This is most often done by declaring your it function with a parameter, from which the framework will infer that the test is asynchronous and pass in a callback:
describe("target", function () {
it("should log error when it occurs", function (cb) {
// ^^^^
});
});
I am using a database library that its callback-based interface looks like this:
var DB = {
insert: function(options, callback) {
}
}
I want to implement a wrapper around this database to convert its callback style API to a promise based API. To do this I have defined the following class:
var DatabaseWrapper = {
init: function(db) {
this.db = db;
},
insert: function(options) {
return Q.denodeify(this.db.insert.bind(this.db))(options);
}
}
I want to write a unit test to ensure that when I call DatabaseWrapper.insert it calls DB.insert. So far my test looks like this:
describe('DatabaseWrapper', function () {
var wrapper, insertSpy, bindStub;
beforeEach(function () {
wrapper = Object.create(DatabaseWrapper);
insertSpy = sinon.spy(function () {
console.log('insertSpy got called');
});
bindStub = sinon.stub();
wrapper.db = {
insert: function (options, callback) {
}
};
sinon.stub(wrapper.db.insert, 'bind').returns(insertSpy);
});
describe('#insert', function () {
it('should delegate to db.insert', function (done) {
wrapper.insert({herp: 'derp'});
expect(wrapper.db.insert.bind).to.have.been.calledOnce;
// This fails but I expect it to succeed
expect(promise).to.have.been.calledOnce;
})
});
});
The DB instance's insert method is actually getting called as after the test fails, as the 'insertSpy got called' message is printed in the console.
But apparently it gets called after the test has failed.
As far as I know, this is due to the way Node's process.nextTick works. So the call to the callback happens after the test fails. Is there a way I can fix this test without relying on third-party libraries (e.g. q-flush)?
You're performing an asynchronous action so it's best to perform an asynchronous test. Adding a setTimeout still leaves you prone to race conditions.
describe('#insert', function () {
it('should delegate to db.insert', function () { // no done here
// note the return here to signal to mocha this is a promise test
return wrapper.insert({herp: 'derp'}).then(function(){
// add expects here, rest of asserts should happen here
expect(wrapper.db.insert.bind).to.have.been.calledOnce;
});
})
});
});
I'm trying to create a module that will fill in form inputs when functional testing, and I'd like to be able to call it from multiple test suites.
Pseudo code for the helper file (helper.js)
module.exports = {
fillForm: function() {
this.findByCssSelector('#firstname')
.click()
.pressKeys('John')
.end()
},
anotherFunction: function() {
// more code
}
}
In the spec for the functional test, I load that module as helper and I can see it execute. However, it seems I can't use this syntax and guarantee that the chained steps execute in the defined order:
'Test filling form data': function() {
return this.remote
.get(require(toUrl(url))
// should happen first
.then(helper.fillForm)
// should happen second
.then(helper.anotherFunction)
// only after the above should the click happen
.findByCsSelector('#submit')
// click evt should show the #someElement element
.click()
.findByCssSelector('#someElement')
.getComputedStyle('display')
.then(style) {
// assertions here
}
It seems that the promise chaining allows the click event to happen before the then callbacks have executed. Is this sort of flow possible with intern?
UPDATE:
For the moment, working around this with this sort of code:
var remote = initTest.call(this, url);
return helpers.fillForm1Data.call(remote)
.otherChainedMethodsHere()
.moreChainedMethods()
.then() {
// assertion code here
where the initTest method does url fetching, window sizing, clearing data, and the fillForm1Data does as you'd expect. But the syntax is pretty ugly this way.
Your helper is not returning any value so it is treated as a synchronous callback and the next thing in the chain is executed immediately. You also cannot return this from a promise helper or it will cause a deadlock (because the Command promise will be waiting for itself to resolve—Intern will throw an error instead if you try to do this), so you need to create a new Command and return that if you want to use the chained Command interface within your helper:
module.exports = {
fillForm: function() {
return new this.constructor(this.session)
.findByCssSelector('#firstname')
.click()
.pressKeys('John');
},
anotherFunction: function() {
// more code
}
};
You can also just return from this.session instead if you don’t care about the convenience of the Command API and can deal with normal promise callback chains:
module.exports = {
fillForm: function() {
var session = this.session;
return session.findByCssSelector('#firstname')
.then(function (element) {
return element.click();
})
.then(function () {
return session.pressKeys('John');
});
},
anotherFunction: function() {
// more code
}
};
Check out this code :
Link
<span>Moving</span>
$('#link').click(function () {
console.log("Enter");
$('#link').animate({ width: 200 }, 2000, function() {
console.log("finished");
});
console.log("Exit");
});
As you can see in the console, the "animate" function is asynchronous, and it "fork"s the flow of the event handler block code. In fact :
$('#link').click(function () {
console.log("Enter");
asyncFunct();
console.log("Exit");
});
function asyncFunct() {
console.log("finished");
}
follow the flow of the block code!
If I wish to create my function asyncFunct() { } with this behaviour, how can I do it with javascript/jquery? I think there is a strategy without the use of setTimeout()
You cannot make a truly custom asynchronous function. You'll eventually have to leverage on a technology provided natively, such as:
setInterval
setTimeout
requestAnimationFrame
XMLHttpRequest
WebSocket
Worker
Some HTML5 APIs such as the File API, Web Database API
Technologies that support onload
... many others
In fact, for the animation jQuery uses setInterval.
You can use a timer:
setTimeout( yourFn, 0 );
(where yourFn is a reference to your function)
or, with Lodash:
_.defer( yourFn );
Defers invoking the func until the current call stack has cleared. Any additional arguments are provided to func when it's invoked.
here you have simple solution (other write about it)
http://www.benlesh.com/2012/05/calling-javascript-function.html
And here you have above ready solution:
function async(your_function, callback) {
setTimeout(function() {
your_function();
if (callback) {callback();}
}, 0);
}
TEST 1 (may output '1 x 2 3' or '1 2 x 3' or '1 2 3 x'):
console.log(1);
async(function() {console.log('x')}, null);
console.log(2);
console.log(3);
TEST 2 (will always output 'x 1'):
async(function() {console.log('x');}, function() {console.log(1);});
This function is executed with timeout 0 - it will simulate asynchronous task
Here is a function that takes in another function and outputs a version that runs async.
var async = function (func) {
return function () {
var args = arguments;
setTimeout(function () {
func.apply(this, args);
}, 0);
};
};
It is used as a simple way to make an async function:
var anyncFunction = async(function (callback) {
doSomething();
callback();
});
This is different from #fider's answer because the function itself has its own structure (no callback added on, it's already in the function) and also because it creates a new function that can be used.
Edit: I totally misunderstood the question. In the browser, I would use setTimeout. If it was important that it ran in another thread, I would use Web Workers.
Late, but to show an easy solution using promises after their introduction in ES6, it handles asynchronous calls a lot easier:
You set the asynchronous code in a new promise:
var asyncFunct = new Promise(function(resolve, reject) {
$('#link').animate({ width: 200 }, 2000, function() {
console.log("finished");
resolve();
});
});
Note to set resolve() when async call finishes.
Then you add the code that you want to run after async call finishes inside .then() of the promise:
asyncFunct.then((result) => {
console.log("Exit");
});
Here is a snippet of it:
$('#link').click(function () {
console.log("Enter");
var asyncFunct = new Promise(function(resolve, reject) {
$('#link').animate({ width: 200 }, 2000, function() {
console.log("finished");
resolve();
});
});
asyncFunct.then((result) => {
console.log("Exit");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Link
<span>Moving</span>
or JSFiddle
This page walks you through the basics of creating an async javascript function.
Since ES2017, asynchronous javacript functions are much easier to write. You should also read more on Promises.
If you want to use Parameters and regulate the maximum number of async functions you can use a simple async worker I've build:
var BackgroundWorker = function(maxTasks) {
this.maxTasks = maxTasks || 100;
this.runningTasks = 0;
this.taskQueue = [];
};
/* runs an async task */
BackgroundWorker.prototype.runTask = function(task, delay, params) {
var self = this;
if(self.runningTasks >= self.maxTasks) {
self.taskQueue.push({ task: task, delay: delay, params: params});
} else {
self.runningTasks += 1;
var runnable = function(params) {
try {
task(params);
} catch(err) {
console.log(err);
}
self.taskCompleted();
}
// this approach uses current standards:
setTimeout(runnable, delay, params);
}
}
BackgroundWorker.prototype.taskCompleted = function() {
this.runningTasks -= 1;
// are any tasks waiting in queue?
if(this.taskQueue.length > 0) {
// it seems so! let's run it x)
var taskInfo = this.taskQueue.splice(0, 1)[0];
this.runTask(taskInfo.task, taskInfo.delay, taskInfo.params);
}
}
You can use it like this:
var myFunction = function() {
...
}
var myFunctionB = function() {
...
}
var myParams = { name: "John" };
var bgworker = new BackgroundWorker();
bgworker.runTask(myFunction, 0, myParams);
bgworker.runTask(myFunctionB, 0, null);
Function.prototype.applyAsync = function(params, cb){
var function_context = this;
setTimeout(function(){
var val = function_context.apply(undefined, params);
if(cb) cb(val);
}, 0);
}
// usage
var double = function(n){return 2*n;};
var display = function(){console.log(arguments); return undefined;};
double.applyAsync([3], display);
Although not fundamentally different than the other solutions, I think my solution does a few additional nice things:
it allows for parameters to the functions
it passes the output of the function to the callback
it is added to Function.prototype allowing a nicer way to call it
Also, the similarity to the built-in function Function.prototype.apply seems appropriate to me.
Next to the great answer by #pimvdb, and just in case you where wondering, async.js does not offer truly asynchronous functions either. Here is a (very) stripped down version of the library's main method:
function asyncify(func) { // signature: func(array)
return function (array, callback) {
var result;
try {
result = func.apply(this, array);
} catch (e) {
return callback(e);
}
/* code ommited in case func returns a promise */
callback(null, result);
};
}
So the function protects from errors and gracefully hands it to the callback to handle, but the code is as synchronous as any other JS function.
Unfortunately, JavaScript doesn't provide an async functionality. It works only in a single one thread. But the most of the modern browsers provide Workers, that are second scripts which gets executed in background and can return a result.
So, I reached a solution I think it's useful to asynchronously run a function, which creates a worker for each async call.
The code below contains the function async to call in background.
Function.prototype.async = function(callback) {
let blob = new Blob([ "self.addEventListener('message', function(e) { self.postMessage({ result: (" + this + ").apply(null, e.data) }); }, false);" ], { type: "text/javascript" });
let worker = new Worker(window.URL.createObjectURL(blob));
worker.addEventListener("message", function(e) {
this(e.data.result);
}.bind(callback), false);
return function() {
this.postMessage(Array.from(arguments));
}.bind(worker);
};
This is an example for usage:
(function(x) {
for (let i = 0; i < 999999999; i++) {}
return x * 2;
}).async(function(result) {
alert(result);
})(10);
This executes a function which iterate a for with a huge number to take time as demonstration of asynchronicity, and then gets the double of the passed number.
The async method provides a function which calls the wanted function in background, and in that which is provided as parameter of async callbacks the return in its unique parameter.
So in the callback function I alert the result.
MDN has a good example on the use of setTimeout preserving "this".
Like the following:
function doSomething() {
// use 'this' to handle the selected element here
}
$(".someSelector").each(function() {
setTimeout(doSomething.bind(this), 0);
});