返回一个 Promise,但得到“无法读取未定义的 属性 'then'”

Returning a Promise, but getting 'Cannot read property 'then' of undefined'

我已经阅读了其他人在这里遇到此错误的示例,但在尝试将 promises 链接在一起时我仍然遇到同样的错误。

在下面的代码中,pegasus(基于 promise 的 http 库:https://github.com/typicode/pegasus)调用 API,返回一些 JSON,然后 returns 一个承诺。我可以使用第一个 then 毫无问题地处理它 returns 返回的数据。这段代码是同步的,最初我没有返回一个承诺,因为我的印象是它没有必要(而且可能仍然没有必要)。在下面的代码中,我尝试将它包装在一个 promise 中,因为这是 Stack Overflow 上其他类似问题的常用解决方案,但似乎也没有解决它。

我仍然收到 TypeError: Cannot read property 'then' of undefined 消息。

var polygonGeo, centroidGeo;
var hexData = pegasus(hexUrl)
  .then(function(data, xhr) {
    return new Promise(function(resolve, reject) {
      var features = data.features;
      var polygons = features.filter(function(feature) {
        return feature.properties.kind === 'Hexagon';
      });
      var centroids = features.filter(function(feature) {
        return feature.properties.kind === 'Centroid';
      });

      polygonGeo = $.extend(true, {}, data);
      centroidGeo = $.extend(true, {}, data);

      polygonGeo.features = polygons;
      centroidGeo.features = centroids;
      if (typeof polygonGeo !== 'undefined' &&
          typeof centroidGeo !== 'undefined') {
        resolve();
      }
    });
}).then(function() {
  console.log('It never reaches here.');
}).catch(function(error) {
  console.log(Error(error));
});

知道我可能哪里出错了吗?

问题是 pegasus 没有实现 A+/Promises。或者,实际上,generally-accepted 意义上的任何类型的承诺。

如果我们查看它的 source code,我们可以看到它的 then 函数没有 return 任何东西:

function pegasus(a, xhr) {
  xhr = new XMLHttpRequest();

  // ...lines omitted...

  xhr.onreadystatechange = xhr.then = function(onSuccess, onError, cb, data) {
      // ...lines omitted, there is no `return` anywhere, at all...
  };

  // Send
  xhr.send();

  // Return request
  return xhr;
}

它正在创建一个 XHR 对象,然后向其添加一个 then 属性 这是一个 非常奇怪的函数 不是一个合适的 then 在 Promises 意义上,return 是 XHR 对象。

适当的 then 函数 return 是一个新的承诺。 pegasus 函数及其 then return 根本不是一个承诺。

@Brideau 对此感到抱歉,then 可能令人困惑。作为@T.J。解释说,这不是真正的 Promise。我将在 README.

中强调该部分

关于不使用 Promises,Pegasus 的想法是它加载得越快,它就可以越快地开始发出请求。

这就是我不使用 Promise polyfill 的原因。这是为了使图书馆尽可能小。出于同样的原因,我也只支持 GET + JSON 请求。

关于 "weird" 代码风格,我正在使用 Byte-saving Techniques。这就是为什么,例如,函数参数被用作变量占位符。

所以一开始应该使用 Pegasus,但之后您可以使用其他库来发出更复杂的请求。

我希望它能让事情变得更清楚:)