【问题标题】:Javascript/jQuery: control execution order (no ajax/php yet)Javascript/jQuery:控制执行顺序(还没有 ajax/php)
【发布时间】:2014-08-18 16:29:29
【问题描述】:

我花了几个小时在网上阅读有关在 Javascript/jQuery 中控制执行顺序的帖子,但我仍然不明白。

我正在尝试编写代码来显示网页上幕后 javascript 的执行进度。我有一个 jsfiddle (http://jsfiddle.net/wlandau/9sbu9myb/) 使用超时来完成此操作。 javascript是

var showProgress = function(x){
    $(".progress").hide();
    $(x).show();   
}

var step1 = function(){
    showProgress(".running");
};

var step2 = function(){
    for(var i = 0; i < 1000000000; ++i) 
        i = i + 1; 
};

var step3 = function(){
    showProgress(".done");
};

$(".begin").click(function(){
    step1();
    setTimeout(step2, 0);
    setTimeout(step3, 0);
});

$(".clear").click(function(){
    $(".progress").hide();   
});

我最终将需要使用 ajax 和 php,并且我已经读到推荐的工具是 when/then、Deferred objects 和 Promise。所以我尝试了(http://jsfiddle.net/wlandau/an8moww6/),但是执行顺序错误。 (当 for 循环运行时,html 页面不会说“正在运行...”。)那个小提琴的 javascript 是

var showProgress = function(x){
    $(".progress").hide();
    $(x).show();   
}

var step1 = function(){
    var def = $.Deferred(); 
    showProgress(".running");
    return def.promise();
};

var step2 = function(){
    var def = $.Deferred(); 
    for(var i = 0; i < 1000000000; ++i) 
        i = i + 1; 
    return def.promise();
};

var step3 = function(){
    var def = $.Deferred(); 
    showProgress(".done");
    return def.promise();
};

var success = function(){
    console.log("success")   
};

var failure = function(){
    console.log("failure")   
};

$(".begin").click(function(){
    $.when(step1(), step2(), step3()).then(success, failure);
});

$(".clear").click(function(){
    $(".progress").hide();   
});

问题 1(第一小提琴):当我在“$(".begin").click(function(){..}" 块中将“step1()”更改为“setTimeout(step1, 0)”时,执行顺序崩溃了,这是为什么呢?

问题 2(第二小提琴):为什么当我尝试使用 when/then/Deferred/promise 时执行顺序错误?

问题 3(第二个小提琴):为什么“成功”函数没有执行?我告诉它打印到控制台,但 Chrome 的 Javascript 控制台什么也没显示。

【问题讨论】:

  • 问题 1:这是指 sn-p 1 还是 2(有或没有延迟)?您能否更具体地了解“崩溃”,您观察到了什么?问题2:究竟什么是“错误”?以意想不到的顺序发生了什么?
  • 问题 1 指的是 sn-p 1,没有延迟。正确的执行顺序是这样的:用户按下“开始”按钮,出现一个显示“正在运行...”的框,出现一个很大的长 for 循环,然后带有“正在运行...”的框被替换为显示“完成”的框。在我在问题 1 和 2 中描述的情况下,“正在运行...”框看起来不够长,无法实际看到。我认为它出现在 for 循环之后,并立即被“完成”替换。盒子。我认为 jsfiddles 比这个解释更清楚。
  • 所以order总是正确的,但timing不正确? “不幸的是”,即使换了setTimeout,第一个小提琴对我来说也很好,你用什么浏览器来体验这个?
  • 我正在使用 Chrome (v36.0.1985.143)。执行顺序和时间有什么区别?
  • 顺序意味着以正确的顺序执行步骤(1-2-3 而不是 2-3-1),而通过时间我指的是步骤之间的(时间)间隔(1-2- 3 而不是 12----3)。

标签: javascript jquery settimeout .when


【解决方案1】:

当我尝试使用 when/then/Deferred/promise(第二个小提琴)时,为什么时间错误?

因为您没有使用任何setTimeouts,所以有效地同步执行所有内容。浏览器在完成处理之前不会重新渲染屏幕,您只会看到最后出现Done

使用 Promises/Deferreds 不会使您的代码异步!您必须自己处理:

function step…(){
    var def = $.Deferred(); 
    setTimeout(function() {
        …
    }, 0);
    return def.promise();
};

另外,一次调用step1(), step2(), step3()(然后将promise 传递给$.when 以等待全部解决)将并行运行异步函数,这不是您想要的。要链接它们,请使用

step1().then(step2).then(step3).then(success, failure);

为什么“成功”函数没有执行(第二个小提琴)?

因为你的承诺永远不会得到解决。当你完成你的异步任务后,你需要告诉 deferred (并且通常传递结果值)。您在代码中的承诺永远挂起,从不执行任何处理程序。

固定:

function step1() {
    var def = $.Deferred();
    setTimeout(function() {
        showProgress(".running");
        def.resolve();
    }, 0);
    return def.promise();
}

function step2() {
    var def = $.Deferred();
    setTimeout(function() {
       for(var i = 0; i < 1000000000; ++i) 
            i = i + 1;
        def.resolve();
    }, 0);
    return def.promise();
}

function step3() {
    var def = $.Deferred();
    setTimeout(function() {
       showProgress(".done");
        def.resolve();
    }, 0);
    return def.promise();
}

由于您的函数本质上不是异步的,您也可以选择立即执行操作,只输入setTimeout(def.resolve, 0) 并仅延迟处理程序;你也可以两者都做。

【讨论】:

  • 我要补充一点,当延迟失败或永远不会调用失败回调时,OP 应该记住调用拒绝。
  • 关于问题 1 我没有证据表明为什么它不能与第三个 setTimeout 一起使用,但猜测是 a) 0 超时太低(实际上至少有 4 毫秒)b) 超时具有相同延迟的安排在一起 - 因此在某些浏览器中优化可能会介入而不是在两者之间进行渲染,就像在同步情况下一样。
  • @MikeCheel:当然,“解决”意味着满足和拒绝,无论是什么合适的。在这种情况下,他们几乎不会失败:-)
  • 由于 OP 似乎不知道必须调用 resolve,所以我想我会提到必须为失败调用 reject。
  • 不。 “同步”代码只是意味着语句一个接一个地执行,阻塞直到它们完成(showStart(); /* loop */; showEnd();)。不过,这也会阻塞渲染,所以我们需要“异步”的非阻塞代码。检查ejohn.org/blog/how-javascript-timers-work 并阅读有关 JavaScript 的 事件循环 (手头没有好的链接)。现在,为了防止出现竞态条件,我们想要“序列化”我们的异步代码,确保正确的顺序。我们可以嵌套回调,也可以使用 Promise。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-06
  • 2016-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多