jQuery推迟:在方法中嵌套承诺,过早回调

时间:2017-11-15 07:50:59

标签: javascript jquery asynchronous promise deferred

我有延迟/承诺的问题。我有一个main函数调用两个必须连续执行的函数。第一个包含一堆必须首先串行执行的异步Web服务调用。但实际上我的第二个函数是在第一个函数中的每个异步反馈都被调用之前调用的。

我构建了一个显示问题的小例子:https://fiddle.jshell.net/qLf1c0uq/

以下是供参考的代码:

function first() {
  $('ul').append("<li>first started</li>");
  let deferred = $.Deferred();
  setTimeout(function() { // Any async function.
    $('ul').append("<li>first ended</li>");
    deferred.resolve();
  }, 2000);
  return deferred.promise();
}

function second(da) {
  $('ul').append("<li>second started</li>");
  let deferred = $.Deferred();
  $('ul').append("<li>second ended</li>");
  deferred.resolve();
  return deferred.promise();
}

function third(da) {
  $('ul').append('<li>third started</li>')
  let deferred = $.Deferred();
  setTimeout(function() {
    $('ul').append("<li>third ended</li>");
    deferred.resolve();
  }, 2000);

  return deferred.promise();
}

function GroupFunction1() {
  let deferred = $.Deferred();
  $('ul').append("<li>Group 1 started</li>");
  var data = "test2";
  $.when(first()).then(function() {
    second(data);
  }).then(function() {
    third("test2");
  }).then(function() {
    $('ul').append("<li>Group 1 ended</li>");
    deferred.resolve();
  });

  return deferred.promise();
}

function GroupFunction2() {
  $('ul').append("<li>Group 2 started</li>");

  $('ul').append("<li>Group 2 ended</li>");
}

$(function() {
  $.when(GroupFunction1()).then(GroupFunction2);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul></ul>

GroupFunction2在第三个函数结束之前启动。我期待它反过来。

任何人都可以提供帮助吗?

谢谢!

2 个答案:

答案 0 :(得分:3)

您需要return回调函数中的承诺。这是承诺链可以等待它们的唯一方式。

此外,您正在滥用Explicit Promise Creation Antipattern。

.then()返回一个承诺。你可以退货。将单个承诺传递到$.when()是没有意义的,因为所有$.when()将要做的就是将其吐出来:

&#13;
&#13;
function first() {
  $('ul').append("<li>first started</li>");
  let deferred = $.Deferred();
  setTimeout(function() { // Any async function.
    $('ul').append("<li>first ended</li>");
    deferred.resolve();
  }, 2000);
  return deferred.promise();
}

function second(da) {
  $('ul').append("<li>second started</li>");
  let deferred = $.Deferred();
  $('ul').append("<li>second ended</li>");
  deferred.resolve();
  return deferred.promise();
}

function third(da) {
  $('ul').append('<li>third started</li>')
  let deferred = $.Deferred();
  setTimeout(function() {
    $('ul').append("<li>third ended</li>");
    deferred.resolve();
  }, 2000);

  return deferred.promise();
}

function GroupFunction1() {
  let deferred = $.Deferred();
  $('ul').append("<li>Group 1 started</li>");
  var data = "test2";

  // v-- here
  return first()      // v-- here
    .then(function() { return second(data); })
    .then(function() { return third("test2"); })
    .then(function() { $('ul').append("<li>Group 1 ended</li>"); });
}

function GroupFunction2() {
  $('ul').append("<li>Group 2 started</li>");

  $('ul').append("<li>Group 2 ended</li>");
}

$(function() {
  GroupFunction1().then(GroupFunction2);
})
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul></ul>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

不是你问题的答案; JLRishe已经解释了为什么你的代码没有等到你的承诺。

这是一个清理,我已经包含了一个小实用程序,它将setTimeout包装到一个Promise中,所以你不必一直这样做,不要在整个地方重复自己。

function first(data) {
  $('ul').append("<li>first started</li>");
  return wait(2000)
    .then(function(){
      $('ul').append("<li>first ended</li>");
    });
}

function second(data) {
  $('ul').append("<li>second started</li>");
  $('ul').append("<li>second ended</li>");
  //let's stay consistent with our API
  //even if we have to return an empty/pointless Promise for that
  return Promise.resolve();
}

function third(data) {
  $('ul').append("<li>third started</li>");
  return wait(2000)
    .then(function(){
      $('ul').append("<li>third ended</li>");
    });
}


function GroupFunction1() {
  $('ul').append("<li>Group 1 started</li>");
  var data = "test2";
  return first(data)
    //.then(wait(1000))  //maybe a little pause in between?
    .then(function(){
      return second(data);
    })
    //.then(wait(1000))  //maybe a little pause in between?
    .then(function(){
      return third(data);
    })
    .then(function() {
      $('ul').append("<li>Group 1 ended</li>");
    });
}

function GroupFunction2() {
  $('ul').append("<li>Group 2 started</li>");

  $('ul').append("<li>Group 2 ended</li>");
  return Promise.resolve(); //again, just staying consistent
}

//DRY. Get rid of all the manual setTiemouts and the Deferreds and wrap them into a function:

//Examples on how to use:
//promise = somePromise.then(wait(1000)).then(someFn);
//promise = wait(1000).then(someFn);
//promise = wait(1000).resolve(42);
//promise = wait(30000).reject("timeout");
const wait = (function(){
	const reject = Promise.reject.bind(Promise);
	const methods = {
		then(a,b){ return this().then(a,b) },
		resolve(value){ return this(value) },
		reject(err){ return this(err).then(reject) }
	};
	return delay => Object.assign(value => new Promise(resolve => void setTimeout(resolve, delay, value)), methods);
})();

$(function() {
  GroupFunction1().then(GroupFunction2);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul></ul>