jQuery延迟承诺进度通知

时间:2016-09-29 10:40:19

标签: promise progress jquery-deferred

我一直在玩承诺并试图建立某种进度通知。

代码以正确的顺序执行所有函数,但进度更新在解析之前执行,而不是在实际发生时执行。

有谁可以指出我做错了什么?

  function start(x) {
    console.log("Start: " + x);
    var promise = process(x);
    console.log("promise returned");
    promise.then(function(data) {
        console.log("Completed: " + data);
    }, function(data) {
        console.log("Cancelled: " + data);
    }, function(data) {
        console.log("In Progress: " + data);
    });
  }

  function process(x) {
    var deferred = $.Deferred();
    var promise = deferred.promise();

    // process asynchronously
    setTimeout(function() {
      for (var i=0 ; i<x ; i++) {
        sleep(1000);
        deferred.notify(i);
      }

      if (x % 2 === 0) {
        deferred.reject(x);
      } else {
        deferred.resolve(x);
      }
    }, 0);

    return promise;
  }

  function sleep(sleepDuration) {
    var now = new Date().getTime();
    while(new Date().getTime() < now + sleepDuration){ /* do nothing */ }
  }

  start(3);

这里小提琴: https://jsfiddle.net/n86mr9tL/

1 个答案:

答案 0 :(得分:1)

使用while()实现的延迟计时器,将&#34;阻止&#34; - 即占用处理器。

阻止不仅会阻止其他javascript运行,还会阻止包括控制台在内的浏览器屏幕的可靠刷新。因此,当deferred.notify(i)console.log("In Progress: " + data)语句被触发时,控制台不会刷新,直到处理器可以自由执行。

不出所料,解决方案在于不使用while()

幸运的是,javascript包含两个内置方法window.setTimeout()window.setInterval(),它们在概念上与while()闲人不同,但履行相同的角色.... 没有阻止

  • window.setInterval(fn, t)每隔t毫秒触发一次函数fn
  • window.setTimeout(fn, t)在t毫秒后触发一次函数fn

两种方法都返回一个不透明的引用,允许它们被取消。

在下面的代码中,start()未经修改,process()经过大量修改,sleep()已消失。

process()现在执行以下操作:

  • 创建一个jQuery Deferred并返回一个从它派生的promise
  • 建立一个1000毫秒(1秒)的setInterval(),其功能如下:
    • 记录被调用的次数,
    • 每秒拨打deferred.notify(),直到计数器i达到指定的最大值x
  • 达到指定的最大值时:
    • 该间隔,否则将无声地剔除 ad infinitum ,将被清除,
    • deferred.resolve()deferred.reject()被叫来解决延期(及其承诺),
function start(x) {
    console.log("Start: " + x);
    process(x).then(function(data) {
        console.log("Completed: " + data);
    }, function(data) {
        console.log("Cancelled: " + data);
    }, function(data) {
        console.log("In Progress: " + data);
    });
}

function process(x) {
    return $.Deferred(function(dfd) {
        var i = 1;
        var intervalRef = setInterval(function() {
            if(i < x) {
                dfd.notify(i++);
            } else {
                clearInterval(intervalRef);
                dfd[(x % 2 === 0)?'reject':'resolve'](x);
            }
        }, 1000);
    }).promise();
}

console.clear();
start(3);

<强> Updated fiddle