【问题标题】:Callback after multiple promises returned before promises resolved in jQuery 2.1, but not 3.1在 jQuery 2.1 中解决承诺之前返回多个承诺后的回调,但不是 3.1
【发布时间】:2018-06-15 02:44:37
【问题描述】:

问题:

我一直在拼命想弄清楚为什么我使用 $.when.apply().then() 编写的一些代码来解决多个承诺然后返回数据似乎不同步,返回一个未解析的promise,然后在回调已经被调用后解析promise。

这是我一直在使用的模拟代码:

format(function(r) {
	console.log('Done!', r);
});

function format(callback) {
	var promises = [];
  var items = [
  {model: 'George'}
  ];
  
  $.each(items, function (i, item) {
        var selectedSeries = item.model;
        promises.push(getSeriesDescription(selectedSeries));
    });
    
    $.when.apply($, promises).then(function (seriesInfo) {
    		console.log('Calling back');
        callback(seriesInfo);
    });
}

function getSeriesDescription(series) {
	return new Promise(function (resolve, reject) {
        getSeriesNotes().then(function (notes) {
            console.log('Processing Notes...');
            var rNotes;
            $.each(notes.data, function () {
                if (series !== 'undefined') {
                    console.log('Checking series ' + this.first_name + ' against ' + series + '...');
                    if (this.first_name == series) {
                        console.log('Series found!');
                        rNotes = this;
                        return false;
                    }
                } 
            });
            if (rNotes !== undefined) {
                console.log('Returning series specific notes...');
                resolve(rNotes);                
            } else {
                resolve(notes);
            }
        });
    });
}

function getSeriesNotes() {
		
    return $.ajax({
        url: 'https://reqres.in/api/users?delay=2',
        dataType: 'json',
        type: 'GET',
        data: '',
    });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

我的发现:

经过大量调试后,我终于意识到意外行为似乎是我使用的 jQuery 版本的结果。下面我有两个使用完全相同的代码的小提琴,使用不同版本的 jQuery。 (我发布 jsfiddles 是因为 StackOverflow 没有 jQuery 的 3.x 版本)

jQuery 2.1.3:

https://jsfiddle.net/persononfire/1epgnfuh/2/

jQuery 3.1.1:

https://jsfiddle.net/persononfire/a9gc0y14/

通过查看控制台中的每一个,您会发现 v3 版本会按照我的预期返回,而 v2 版本则不会。

预期结果:

处理笔记...

(index):58 检查系列 George 对 George...

(索引):找到 60 个系列!

(index):67 返回系列特定笔记...

(index):46 回调

(索引):31 完成! {id: 1, first_name: "George", last_name: "Bluth", 头像: "https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg"}

2.1.3 版首先返回最后两行,然后按照我期望的顺序返回所有其他内容。

问题:

所以我的问题是;为什么 jQuery 的两个版本之间的结果存在差异?我无法在版本文档中找到任何在我看来会导致两个 jQuery 版本之间的行为差​​异的内容。

我感谢任何对此的见解,以对我自己的启发。

【问题讨论】:

  • 您是否需要使其与 v2 一起使用,或者这只是一个兴趣问题?
  • 不确定到底有什么区别,但这似乎是由于使用Promise(),因为在v2中使用$.Deferred()可以正常工作
  • @T.J.Crowder 好吧,两者都有。我被锁定在 2 中,但我想我可以弄清楚如何解决它。但我很好奇其中的区别。
  • 这是我之前评论的证明:jsfiddle.net/1epgnfuh/7

标签: javascript jquery ajax promise


【解决方案1】:

jQuery v2 的 Deferred 和 Promise 不符合 Promises/A+ 规范(部分原因是它们早于当前版本)并且不能与原生 Promises 可靠地互操作。 jQuery v3 fixed them 所以它们可以与原生 Promise 互操作。 (虽然$.when 并不完全兼容。)

另外:如果你正在处理原生承诺,我建议尽可能远离$.when。请改用Promise.all。 :-) 事实上,我的偏好是要么完全留在 jQuery Deferred/promise 生态系统内,要么完全在它之外(通过尽早将任何 jQuery Deferreds/Promises 转换为真实的)。

这是一个相当简单的 $.when 不使用原生承诺的例子。

jQuery v2,不工作:

function timeout(value, delay) {
  console.log("creating promise for " + value);
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("resolving promise for " + value);
      resolve(value);
    }, delay);
  });
}

$.when(
  timeout(1, 100),
  timeout(2, 200),
  timeout(3, 300)
).then(result => {
  console.log("then on $.when: ", result);
});
.as-console-wrapper {
  max-height: 100% !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

jQuery v3,虽然请注意返回值只是第一个承诺的值(因为$.whenthen 回调的调用是非标准的:它将每个承诺结果作为离散参数传递) :

function timeout(value, delay) {
  console.log("creating promise for " + value);
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("resolving promise for " + value);
      resolve(value);
    }, delay);
  });
}

$.when(
  timeout(1, 100),
  timeout(2, 200),
  timeout(3, 300)
).then(result => {
  console.log("then on $.when: ", result);
});
.as-console-wrapper {
  max-height: 100% !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

旁注:getSeriesDescription 中的new Promise 没有任何理由,getSeriesNotes().then已经给了你一个可以使用的承诺。有趣的是,如果你解决了这个问题,它甚至可以在 jQuery v2 中使用:

format(function(r) {
  console.log('Done!', r);
});

function format(callback) {
  var promises = [];
  var items = [{
    model: 'George'
  }];

  $.each(items, function(i, item) {
    var selectedSeries = item.model;
    promises.push(getSeriesDescription(selectedSeries));
  });

  $.when.apply($, promises).then(function(seriesInfo) {
    console.log('Calling back');
    callback(seriesInfo);
  });
}

function getSeriesDescription(series) {
  return getSeriesNotes().then(function(notes) {
    console.log('Processing Notes...');
    var rNotes;
    $.each(notes.data, function() {
      if (series !== 'undefined') {
        console.log('Checking series ' + this.first_name + ' against ' + series + '...');
        if (this.first_name == series) {
          console.log('Series found!');
          rNotes = this;
          return false;
        }
      }
    });
    if (rNotes !== undefined) {
      console.log('Returning series specific notes...');
      return rNotes;
    } else {
      return notes;
    }
  });
}

function getSeriesNotes() {

  return $.ajax({
    url: 'https://reqres.in/api/users?delay=2',
    dataType: 'json',
    type: 'GET',
    data: '',
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

【讨论】:

  • @Ryan-Gibbs,查看JQuery 3.0 Release Notes重大变化了解更多详情
  • Promises/A+ 规范对我来说是难题的重要组成部分,我没有意识到这一点。所以当他们在变更文档中提出它时,我没有意识到这是影响事情的原因。感谢您的全面介绍,是时候重构了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-15
  • 2016-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多