edit: important note using jquery 1.7.2, , no cannot changed version
i'm new promises , trying wrap head around them. i'm trying execute series of functions in order, waiting them complete before creating child views (this in backbone.js). here's code:
initialize: function () { console.log('appview::initialized!'); var _this = this; $.when( _this.processcookies() ) .then( _this.loadadscripts() ) .then( _this.createchildviews() ); }, processcookies: function () { var def = $.deferred(); console.log('(1) process cookies'); return def.resolve(); }, /** * instantiates new instances of child views. */ createchildviews: function () { var _this = this; console.log('(4) creating child views'); }, loadadscripts: function () { var _this = this, def = $.deferred(); $.when( _this.insertscript({ name: 'example1', async: false, src: '//www.example.com/script1.js', }), _this.insertscript({ is_mobile: is_mobile, name: 'example2', async: true, src: '//example.com/script2.js' }) ) .done(function () { console.log('(3) scripts loaded'); def.resolve(); }); }, insertscript: function (script) { var def = $.deferred(), protocol = (document.location.protocol === 'https:' ? 'https:' : 'http:'); // dont script 2 on mobile. if (script.name === 'example2' && script.is_mobile) { console.log('skipping script'); return def.resolve(); } var promise = $.ajax({ datatype: 'script', cache: false, async: script.async, url: protocol + script.src, }); promise.done( function () { console.log('(2) single script loaded'); return def.resolve(); }); },
so, desired flow here is:
- when
processcookies()
function completed, - execute
loadadscripts
function 2a.insertscript()
fires, script 1 loads 2b.insertscript()
fires, script 2 loads - when both scripts finished, execute
createchildviews
function.
so, observing console.log()
placeholders in code, expect see in console:
'(1) process cookies' '(2) single script loaded' '(2) single script loaded' '(3) scripts loaded' '(4) creating child views'
however actually see is:
'(1) process cookies' '(3) scripts laoded' '(4) creating child views' '(2) single script loaded' '(2) single script loaded'
what wrong promises, , why not executing in expected order?
$.when( _this.processcookies() ) .then( _this.loadadscripts() ) .then( _this.createchildviews() );
appear calling loadscripts()
, createchildviews()
immediately, instead try referencing function names @ .then(_this.loadadscripts)
callbacks .
return def.resolve()
returns jquery.deferred()
object , not jquery promise object ; try adding .promise()
after .resolve()
return jquery promise object .
jquery.ajax()
returns jquery promise object ; not necessary create new jquery $.deferred()
object, return $.ajax()
initialize: function () { console.log('appview::initialized!'); var _this = this; $.when( _this.processcookies() ) // reference function name, not invoked .then( _this.loadadscripts ) .then( _this.createchildviews ); }, processcookies: function () { // no asynchronous operations appear here, // no need include `$.deferred()` or `.promise()` object // var def = $.deferred(); console.log('(1) process cookies'); // return jquery promise object, not deferred object // return def.resolve().promise(); }, /** * instantiates new instances of child views. */ createchildviews: function () { var _this = this; console.log('(4) creating child views'); }, loadadscripts: function () { //var _this = this, // def = $.deferred(); return $.when( _this.insertscript({ name: 'example1', async: false, src: '//www.example.com/script1.js', }), _this.insertscript({ is_mobile: is_mobile, name: 'example2', async: true, src: '//example.com/script2.js' }) ) .done(function () { console.log('(3) scripts loaded'); // def.resolve(); }); }, insertscript: function (script) { // var def = $.deferred(), protocol = (document.location.protocol === 'https:' ? 'https:' : 'http:'); // dont script 2 on mobile. // if (script.name === 'example2' && script.is_mobile) { // console.log('skipping script'); // return def.resolve().promise(); // } var promise = script.name === 'example2' && script.is_mobile ? $.when() : $.ajax({ datatype: 'script', cache: false, async: script.async, url: protocol + script.src, }); promise.done( function () { console.log('(2) single script loaded'); // def.resolve(); }); },
edit: important note using jquery 1.7.2, , no cannot changed version
edit, updated
expected order may not possible using jquery version 1.7.2 , without modifying source.
appear return expected order when using jquery version 1.8+ , following update of deferred.then ; see http://blog.jquery.com/2012/08/09/jquery-1-8-released/ , http://bugs.jquery.com/ticket/11010
1.8.0
var dfd = { initialize: function () { console.log('appview::initialized!'); _this = dfd; $.when(_this.processcookies()) // reference function name, not invoked .then(_this.loadadscripts) .then(_this.createchildviews); }, processcookies: function () { // no asynchronous operations appear here, // no need include `$.deferred()` or `.promise()` object var def = $.deferred(function (d) { settimeout(function () { d.resolve('(1) process cookies') }, math.floor(math.random() * 1000)); }).promise(); def.then(function (msg) { console.log(msg); }); return def.promise() }, /** * instantiates new instances of child views. */ createchildviews: function () { _this = dfd; console.log('(4) creating child views'); }, loadadscripts: function () { _this = dfd; return $.when.apply(_this, [_this.insertscript({ name: 'example1', async: false, src: '//www.example.com/script1.js', }), _this.insertscript({ is_mobile: true, name: 'example2', async: true, src: '//example.com/script2.js' })]).then(function () { console.log('(3) scripts loaded'); }) }, insertscript: function (script) { // var def = $.deferred(), protocol = (document.location.protocol === 'https:' ? 'https:' : 'http:'); // dont script 2 on mobile. // if (script.name === 'example2' && script.is_mobile) { // console.log('skipping script'); // return def.resolve(); // } var promise = $.when( script.name === 'example2' && script.is_mobile ? $.deferred(function (d) { settimeout(function () { d.resolve('(2) skipping script', protocol + script.src) }, math.floor(math.random() * 1000)) }).promise() : $.deferred(function (d) { settimeout(function () { d.resolve('(2) single script loaded', protocol + script.src) }, math.floor(math.random() * 1000)) }).promise()) return promise.then(function(msg) { console.log(msg) }); } }; dfd.initialize();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
1.72
var dfd = { initialize: function () { console.log('appview::initialized!'); _this = dfd; $.when(_this.processcookies()) // reference function name, not invoked .then(_this.loadadscripts) .then(_this.createchildviews); }, processcookies: function () { // no asynchronous operations appear here, // no need include `$.deferred()` or `.promise()` object var def = $.deferred(function (d) { settimeout(function () { d.resolve('(1) process cookies') }, math.floor(math.random() * 1000)); }).promise(); def.then(function (msg) { console.log(msg); }); return def.promise() }, /** * instantiates new instances of child views. */ createchildviews: function () { _this = dfd; console.log('(4) creating child views'); }, loadadscripts: function () { _this = dfd; return $.when.apply(_this, [_this.insertscript({ name: 'example1', async: false, src: '//www.example.com/script1.js', }), _this.insertscript({ is_mobile: true, name: 'example2', async: true, src: '//example.com/script2.js' })]).then(function () { console.log('(3) scripts loaded'); }) }, insertscript: function (script) { // var def = $.deferred(), protocol = (document.location.protocol === 'https:' ? 'https:' : 'http:'); // dont script 2 on mobile. // if (script.name === 'example2' && script.is_mobile) { // console.log('skipping script'); // return def.resolve(); // } var promise = $.when( script.name === 'example2' && script.is_mobile ? $.deferred(function (d) { settimeout(function () { d.resolve('(2) skipping script', protocol + script.src) }, math.floor(math.random() * 1000)) }).promise() : $.deferred(function (d) { settimeout(function () { d.resolve('(2) single script loaded', protocol + script.src) }, math.floor(math.random() * 1000)) }).promise()) return promise.then(function(msg) { console.log(msg) }); } }; dfd.initialize();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
Comments
Post a Comment