我做了一个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
2
但在jquery 3中它将呈现
1
2
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
答案 0 :(得分:1)
毕竟摆弄它很突出:这个问题没有真正的解决办法;至少没有一个不是非常hackish或没有改变整个设置/工作流程。
为了完整起见,我保留原样的“答案”(查看“LOG”下方的所有内容)并添加一些背景信息。
https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous
jQuery中的文档就绪处理由 自jQuery 1.6以来的jQuery.Deferred实现。作为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>'); }); });
我试图不要过多地依赖这样的订单,但这样的代码会变得非常脆弱。我认为我们在技术上并不保证订单得到保留,但现在就是这样。
通常更好的解决方案是将脚本放在正文的末尾,然后将函数包装在$中是不必要的。
您可以搜索要追加的字符串中的所有脚本。然后使用正则表达式搜索所有“$(function(){...})”事件,然后插入一个像“$(function(){...; executionHandler()})”这样的函数,它将倒计时直到所有这些结构已解决,然后设置一个外部承诺作为resovled。但是,正如我在开始时所说的那样,这将是相当严重的,也可能非常容易出错。
版本1,2,2.1和3都使用jQuery版本1.12.4,2.2.4和3.2.1进行了测试,并且应该适用于jQuery 1.8及更高版本的所有版本。
$.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>');
});
});
被踢了
// $.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 )
提供一种基于零个或多个Thenable对象执行回调函数的方法,通常是表示异步事件的Deferred对象。
[...]
例如,jQuery.ajax()返回的jqXHR对象是一个与Promise兼容的对象,可以使用[...]
jQuery.get( url [, data ] [, success ] [, dataType ] )
[...]是一个简写的Ajax函数[...]
deferred.always( alwaysCallbacks [, alwaysCallbacks ] )
添加要在解析或拒绝Deferred对象时调用的处理程序。
deferred.then( doneFilter [, failFilter ] [, progressFilter ] )
添加要在Deferred对象解析,拒绝或仍在进行中时调用的处理程序。