Skip to content

Instantly share code, notes, and snippets.

@binfeng
Forked from Heshyo/q_example.js
Last active August 29, 2015 14:04
Show Gist options
  • Save binfeng/5a4bd819c8d7c96dd898 to your computer and use it in GitHub Desktop.
Save binfeng/5a4bd819c8d7c96dd898 to your computer and use it in GitHub Desktop.
// Q sample by Jeff Cogswell
/*===========
We want to call these three functions in sequence, one after the other:
First we want to call one, which initiates an ajax call. Once that ajax call
is complete, we want to call two. Once two's ajax call is complete, we want to call three.
BUT, we don't want to just call our three functions in sequence, as this quick
demo will show. Look at this sample function and think about what order
the console.log calls will happen:
===========*/
function demo() {
$.ajax( {
url: '/',
success: function() {
console.log('AJAX FINISHED');
}
});
}
console.log('Calling demo');
demo();
console.log('Finished calling demo');
/*====
The function returns almost immediately, before the ajax call is complete. That means we will likely see 'Finished calling demo' before we see the results of the ajax call:
====*/
//Calling demo
//Finished calling demo
//AJAX FINISHED
/*====
If we want to chain a following function, when do we call it? We call it from inside the success function:
====*/
function demo() {
$.ajax( {
url: '/',
success: function() {
console.log('AJAX FINISHED');
// >>>> THIS IS WHEN you would call another function <<<<<
}
});
}
/* ==============
Now let's try using q.
=============*/
function one(arg) {
var deferred = Q.defer(); // Don't worry yet what this is until after you understand the flow
console.log("Starting one's ajax with arg: " + arg);
$.ajax( {
url: '/',
success: function() {
// Here's where you want to call the next function in the
// list if there is one. To do it, call deferred.resolve()
console.log('Finished with one. Ready to call next.');
deferred.resolve("This is one's result");
}
});
// The deferred object has a "promise" member, which has a "then" function
return deferred.promise;
}
function two(arg) {
var deferred = Q.defer();
console.log("Starting two's ajax with arg: " + arg);
$.ajax( {
url: '/',
success: function() {
// Again, this is where you want to call the next function
// in the list if there is one.
console.log('Finished with two. Ready to call next.');
deferred.resolve("This is two's result");
}
});
// The deferred object has a "promise" member, which has a "then" function
return deferred.promise;
}
function three(arg) {
var deferred = Q.defer();
console.log("Starting three's ajax with arg: " + arg);
$.ajax( {
url: '/',
success: function() {
// Again, this is where you want to call the next function
// in the list if there is one.
console.log('Finished with three. Ready to call next if there is one.');
deferred.resolve("This is three's result");
}
});
// The deferred object has a "promise" member, which has a "then" function
return deferred.promise;
}
function four(arg) {
console.log("Starting four with arg: " + arg);
console.log("Finished synchronous four");
}
// Test it out. Call the first. Pass the functions (without calling them, so no parentheses)
// into the "then" calls.
one("arg given to one")
.then(two)
.then(three)
.then(four);
/* =====
Think about where the "then" function comes from. Each function creates a new defer instance
and returns that object's promise member. That promise object has a "then" function. On return
from the first function, you get back a defer function, and call the "then" function, passing
the *next* function that is to be called. Internally, Q stores that function. When your ajax
call returns, in your "success" function, you call the next function by calling deferred.resolve().
======*/
// Some more examples:
var step1 = function () {
console.log("This is step 1");
};
var step2 = function () {
console.log("This is step 2");
};
var step3 = function () {
console.log("This is step 3");
};
// Note the following can be simply rewritten as :
// Q.fcall(step1).then(step2).then(step3)
var promise1 = Q.fcall(step1); // this will cause step1 to run asynchronously (queued for event loop)
var promise2 = promise1.then(step2); // step2 won't run until promise1 is fulfilled
// note the promise must have a then method, which returns another promise
var promise3 = promise2.then(step3); // step3 won't run until promise2 is fulfilled
// Some more:
function getValue() {
var d = Q.defer();
setTimeout(function() {
d.resolve('ok');
}, 100);
return d.promise;
}
function getError() {
var d = Q.defer();
setTimeout(function() {
d.reject('error');
}, 100);
return d.promise;
}
// 1. Fulfilled, fulfillment handler returns a value: simple functional transformation
getValue()
.then(function(val) {
return val;
})
.then(
function(val) {
console.log(val);
},
function(err) {
console.log(err.message);
}
);
// 2. Fulfilled, fulfillment handler throws an exception: getting data, and throwing an exception in response to it
getValue()
.then(function(val) {
throw new Error('fulfillment handler error');
})
.then(
function(val) {
console.log(val);
},
function(err) {
console.log(err.message);
}
);
// 3. Rejected, rejection handler returns a value: a catch clause got the error and handled it
getError()
.then(null, function(err) {
return 'fixed';
})
.then(
function(val) {
console.log(val);
},
function(err) {
console.log(err.message);
}
);
// 4. Rejected, rejection handler throws an exception: a catch clause got the error and re-threw it (or a new one)
getError()
.then(null, function(err) {
throw new Error('rejection handler error');
})
.then(
function(val) {
console.log(val);
},
function(err) {
console.log(err.message);
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment