我做了一个jsbin来显示问题: http://jsbin.com/dexeqiz/edit?html,js,output
有这个 html:
<div id='log'></div>
<div id='scripts'></div>
和 js:
$.get('...', function(){
$('#scripts')
.append("<script>$(function(){$('#log').append('<p>3</p>');});</script>");
$('#log').append('<p>1</p>');
$('#log').append('<p>2</p>');
});
在 jquery 1 和 2 中
它将在 #log 中呈现:
3
1
阿拉伯数字
但在 jquery 3 中,它将呈现
1
阿拉伯数字
3
(所以只有在整个 ajax 处理程序完成后才添加 3(
这是一个问题,因为有时我的代码期望在调用下一行之前执行之前附加在该行中的代码
现在我唯一的解决方法是将.append(newhtml)
后的代码放在setTimeout
中,但我宁愿不这样做,因为它对用户来说看起来稍微慢一些。我宁愿有类似$.when(append).done(function(){code})
更新:似乎发生这种情况是因为从 jQuery 3 脚本开始,用于文档就绪$(function(){});
加载异步 (https://github.com/jquery/jquery/issues/1895( 和 这是我当前的解决方案:http://jsbin.com/xayitec/edit?html,js,output
毕竟摆弄它很突出:这个问题没有真正的解决方案; 至少没有不是很黑客或不改变整个设置/工作流程。
为了完整起见,我将我的"答案"保留原样(请参阅"LOG"下面的所有内容(并添加一些背景信息。
https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous
jQuery中的文档就绪处理由 jQuery.自jQuery 1.6以来的延迟实现。作为jQuery的一部分 3.0 与 Promises/A+ 标准的一致性,即使文档当前已准备就绪,也会异步调用文档就绪处理程序 添加处理程序的点。这提供了一致的代码 与文档是否准备就绪无关的执行顺序 或不。
https://github.com/jquery/jquery/issues/3773#issuecomment-325999054
由于您将脚本标记中的代码包装为 $,因此您还可以将 其他行:
$.get('...', function(){ $('#somediv') .append( "somehtml<script>$(function(){$('#log').append('<p>3</p>');});/script>" ); $(function(){ $('#log').append('<p>1</p>'); $('#log').append('<p>2</p>'); }); });
我尽量不要过分依赖这样的顺序,但是,这样的代码可能会变得非常脆弱。我认为我们在技术上不能保证秩序得到维护,但现在就是这种情况。
通常更好的解决方案是将脚本放在正文的末尾,然后不需要将函数包装在 $ 中。
- https://github.com/jquery/jquery/issues/1895
- https://github.com/jquery/jquery/pull/2126
还有一个想法 - 非常黑客
您可以在将追加的字符串中搜索所有脚本。然后使用正则表达式搜索所有"$( function(({...} (",然后插入一个函数,如"$( function(({...;executionHandler((} (",这将倒计时,直到解析所有这些构造,然后将外部承诺设置为重新创建。但正如我在开始时所说,这将是相当黑客的,也可能很容易出错。
.LOG
版本 1、2、2.1 和 3 都使用 jQuery 版本1.12.4、2.2.4 和 3.2.1 进行测试,并且应该可以很好地与 jQuery 1.8 及更高版本的所有版本配合使用。
版本 1
$.get('...', function(){
// make shure that $Deferred is in scope of all involved functions
window.$Deferred = $.Deferred(); // get jQuery deferred object
$('#scripts').append(
"hi<script>$(function(){$('#log').append('<p>3</p>');});</script>" + // append your common stuff
"<script>$(function(){$Deferred.resolve();})</script>" // add this line to resolve window.$Deferred
);
$Deferred.always(function() {
// execute code after $Deferred was resolved or rejected
$('#log').append('<p>1</p>');
$('#log').append('<p>2</p>');
});
});
版本 2
被踢了一脚
版本 3
// $.get returns a jqXHR object which is a promise-compatible object
$.when($.get('...', function() {
$('#scripts').append(
"hi<script>$(function(){$('#log').append('<p>3</p>');});</script>"
)
})).always(function( data, textStatus, jqXHR|errorThrown ) {
// execute code when $.get is done or fails
$('#log').append('<p>1</p>');
$('#log').append('<p>2</p>');
});
或者或者
$.when($.get('...', function() {
$('#scripts').append(
"hi<script>$(function(){$('#log').append('<p>3</p>');});</script>"
)
})).then(
function( data, textStatus, jqXHR ) {
// success callback
},
function( jqXHR, textStatus, errorThrown ) {
// fail callback
}
);
详
jQuery.when( deferreds )
提供一种基于零个或多个可调用对象(通常是表示异步事件的延迟对象(执行回调函数的方法。
[...]
例如,jQuery.ajax(( 返回的 jqXHR 对象是一个与 Promise 兼容的对象,可以使用 [...]jQuery.get( url [, data ] [, success ] [, dataType ] )
[...]是一个简写的Ajax函数[...]
deferred.always( alwaysCallbacks [, alwaysCallbacks ] )
添加在解析或拒绝延迟对象时要调用的处理程序。
deferred.then( doneFilter [, failFilter ] [, progressFilter ] )
添加在解析、拒绝或仍在处理延迟对象时要调用的处理程序。
引用
- jQuery.Deferred((
- deferred.when((
- deferred.then((
- deferred.always((
- jQuery.ajax((
- jQuery.get((