将ES6 Promises与JQuery Promises混合使用

时间:2016-03-28 03:49:53

标签: javascript jquery angularjs promise ecmascript-6

我使用过$ q(Angular.js)并经常在.then调用中返回promises。结果是下一个.then调用将等待先前的承诺完成。

我现在正在使用本机es6承诺尝试“宣传”##一个基于回调的库,我无法这样做。

问题是.then链中的下一个值是 promise对象,而不是该promise的已解析值。它在解析promise之前调用下一个.then值,只返回最后一个返回值。

有没有等待先前的承诺解决?

示例:

$.ajax({
    url: "//localhost:3000/api/tokens",
    type: "POST",
    data: JSON.stringify({
      user: {
        email: 'admin@admin.com',
        password: 'password123'
      }
    }),
    contentType: "application/json"
})
.then(data => data.token.encoded)         // OK
.then(token => Farmbot({ token: token })) // OK
.then(function(bot){                      // OK
  return new Promise(function(resolve, reject) {
    bot.connect(function(){ resolve(bot); });
  });
}, errorr)
.then(function(bot){ // NOT OK!
  // passes in an unresolved promise object, which is useless.
  //
  bot; // => {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
});

我的问题是:

ES6承诺会等待之前.then的承诺解决吗?

2 个答案:

答案 0 :(得分:22)

问题源于尝试在Deferred promises链中使用原生Promise

目前(jQuery 1.8 - 2.x),jQuery对.then()的定义仅识别库支持链接时自己的类型。

因此,您可以改为返回$.Deferred()承诺:

// ...
.then(function(bot){
  return $.Deferred(function(defer) {
    bot.connect(function(){ defer.resolve(bot); });
  });
}, errorr)
// ...

或者,您可以使用Promise.resolve(thenable)$.Deferred()提供的初始$.ajax()转换为原生Promise,以便您使用原生.then()在整个链中,它将识别返回的new Promise()(以及$.Deferred()):

Promise.resolve($.ajax({
  // ...
}))
.then(data => data.token.encoded)
// ...

或者,您可以尝试jQuery 3.0,currently in beta

  

jQuery.Deferred现在是Promises / A +兼容

     

jQuery.Deferred对象已更新,与Promises / A +和ES2015 Promises兼容,并使用Promises/A+ Compliance Test Suite进行验证。 [...]

有了它,您的原始代码段应该按预期工作而不进行任何修订。

答案 1 :(得分:3)

  

ES6承诺是否等待之前的.then承诺解决?

这样说:ES6承诺永远不会使用promise或者then对象调用.then(onFulfilled)函数。仅使用非承诺值调用Onfulfilled侦听器。

在信任它们之前将jQuery“thenable”对象转换为ES6 Promises可以解决问题:

var jqPromise = $.ajax({
    url: "//localhost:3000/api/tokens",
    type: "POST",
    data: JSON.stringify({
      user: {
        email: 'admin@admin.com',
        password: 'password123'
      }
    }),
    contentType: "application/json"
})
.then(data => data.token.encoded)         // OK
.then(token => Farmbot({ token: token })) // OK

; 

var es6Promise = Promise.resolve(jqPromise); // convert to ES6 promise

es6Promise.then(function(bot){                      // OK
  return new Promise(function(resolve, reject) {
    bot.connect(function(){ resolve(bot); });
  });
}, errorr)
.then(function(bot){ // will not pass in unfulfilled promise

  // process bot value

});