jQuery推迟了诺言的执行顺序吗? [英] jQuery deferred promises executing out of order?
问题描述
重要说明,这是使用jQuery 1.7.2,不能从该版本进行更改
我对诺言并不陌生,并试图将我的头缠在诺言上.我试图依次执行一系列功能,等待它们完成之后再创建一些子视图(这在Backbone.js中).这是我的代码:
I'm new to promises and trying to wrap my head around them. I'm trying to execute a series of functions in order, waiting for them to complete before creating some child views (this is in Backbone.js). Here's my 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 the 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) ALL 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, the desired flow here is:
-
processCookies()
功能完成后, - 执行
loadAdScripts
函数 2a.insertScript()
触发,脚本1已加载 2b.insertScript()
触发,脚本2已加载 - 两个脚本完成后,执行
createChildViews
函数.
- When the
processCookies()
function is completed, - execute
loadAdScripts
function 2a.insertScript()
fires, script 1 loads 2b.insertScript()
fires, script 2 loads - when BOTH scripts are finished, execute
createChildViews
function.
因此,观察代码中的console.log()
占位符,我期望可以在控制台中看到:
so, observing the console.log()
placeholders in the code, I expect to see in my console:
'(1) PROCESS COOKIES'
'(2) SINGLE SCRIPT LOADED'
'(2) SINGLE SCRIPT LOADED'
'(3) ALL SCRIPTS LOADED'
'(4) CREATING CHILD VIEWS'
但是我实际上看到的是:
'(1) PROCESS COOKIES'
'(3) ALL SCRIPTS LAODED'
'(4) CREATING CHILD VIEWS'
'(2) SINGLE SCRIPT LOADED'
'(2) SINGLE SCRIPT LOADED'
我的诺言有什么问题,为什么它们没有按预期的顺序执行?
What is wrong with my promises, and why are they not executing in the expected order?
推荐答案
$.when( _this.processCookies() )
.then( _this.loadAdScripts() )
.then( _this.createChildViews() );
似乎正在立即调用loadScripts()
,createChildViews()
,而是尝试在.then(_this.loadAdScripts)
回调中引用函数名称.
appear to be calling loadScripts()
, createChildViews()
immediately, instead try referencing function names at .then(_this.loadAdScripts)
callbacks .
return def.resolve()
返回jQuery.Deferred()
对象,而不是jQuery Promise对象;尝试在.resolve()
之后添加.promise()
以返回jQuery Promise对象.
return def.resolve()
returns jQuery.Deferred()
object , not jQuery promise object ; try adding .promise()
after .resolve()
to return jQuery promise object .
jQuery.ajax()
返回jQuery Promise对象;不必创建新的jQuery $.Deferred()
对象,可以返回$.ajax()
jQuery.ajax()
returns jQuery promise object ; not necessary to create new jQuery $.Deferred()
object, could 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 to 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 the 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) ALL 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();
});
},
重要说明,此操作使用的是jQuery 1.7.2,不能,不能 从此版本更改
IMPORTANT NOTE this is using jQuery 1.7.2, and no it cannot be changed from this version
编辑,已更新
在不修改源代码的情况下,使用jQuery 1.7.2版可能无法达到预期的顺序.
Expected order may not be possible using jQuery version 1.7.2 , without modifying source.
在使用 deferred.then 的更新后,使用jQuery 1.8+版本时似乎返回了预期的顺序. ;参见 http://blog.jquery.com/2012/08 /09/jquery-1-8-released/, http://bugs.jquery.com /ticket/11010
Appear to 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 to 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 the 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) ALL 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 to 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 the 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) ALL 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>
这篇关于jQuery推迟了诺言的执行顺序吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!