12

我担心使用 JQuery 兼容的 Promise 对 Parse 的引用,因为我读过 jQuery Promise允许消费者改变 Promise 的状态。是否可以在 Parse JavaScript SDK中使用另一个已知符合Promises/A+的 Promise 实现(例如ECMAScript 6 实现Bluebird )?

通常我会假设这是不可能的,但是在 Parse JavaScript SDK 的 v1.4.2 中,Parse.Promise 的实现将属性“_isPromisesAPlusCompliant”定义为 false,然后在库中的各种函数中检查该属性。

注意这个问题最初是在Parse Developers group上提出的,但没有收到任何回复。

4

3 回答 3

5

你可以使用原生的 Promises,或者一个好的 polyfill。您可以在 Promise.resolve 调用中封装任何 thenable(具有公共 then 方法的 Promise 类对象),如下所示:

var promise = Promise.resolve($.getJSON("/something.json"));

这也将有一个 then 方法,但没有任何头痛。它应该仍然有效。

于 2015-06-28T11:43:42.673 回答
5

我担心 Parse 使用 jQuery 兼容的 Promise,因为我已经读过 jQuery Promise 允许消费者改变 Promise 的状态。

你不需要担心。“jQuery 兼容”可能意味着很多事情,Parse 承诺当然不允许消费者改变他们的状态1(因为 jQuery 多年来也没有这样做)。顺便说一句,它们也是 A+“兼容”的 :-)

1:通过公共方法。所以不超过大多数其他实现,也就是说。

是否可以使用已知与 Parse JavaScript SDK 兼容的 Promises/A+ 的另一个 Promise 实现?

是的。Parse SDK 确实返回了有效的 A+ thenables,这意味着您可以从then您最喜欢的 Promise 实现的回调中返回 Parse Promise,并期望它可以完美地工作:

myCompliantPromise.then(function(res) {
    return parse_query.get(…);
}).then(…)

您还可以使用 将它们转换为有效的实现承诺Promise.resolve,例如:

Promise.resolve(parse_query.get(…)).then(…);

通常我会假设这是不可能的,但是在 Parse JavaScript SDK 的 v1.4.2 中,Parse.Promise 的实现定义了属性_isPromisesAPlusCompliantfalse然后在库中的各种函数中检查该属性。

他!虽然不幸的是没有记录,但这个标志确实允许你在你的应用程序中使原生 Parse.com 承诺库 A+ 兼容:

Parse.Promise._isPromisesAPlusCompliant = true;

更新:在较新的版本中,这不会作为下划线属性公开,而是您必须调用(未记录的)Parse.Promise.enableAPlusCompliant()方法。有关详细信息,请参阅问题 #57

我已经查看了代码,这个标志基本上改变了 3 件事:

  • 回调中的异常then被捕获并导致结果承诺被拒绝,而不是全局错误。所以你可以throw在它们中使用。
  • 如果你returnonRejected回调(第二个参数then)的值,错误应该被处理,结果承诺被履行而不是被拒绝。
  • 所有then回调都是异步执行的。

这些确实解决了当前jQueryDeferred实现所固有的问题。

我假设 Parse 计划静默迁移此true设置以成为默认设置,并正在测试它是否会破坏用户的任何内容。我猜即使尚未记录,使用它也很安全。

我想让所有 Parse API 返回我的自定义库的承诺。

这不是那么简单,虽然它可以做到。基本上有两种方法:

  • 通过组合它们来装饰 API 中的所有承诺返回方法Promise.resolve,这基本上是 @dancamper 建议的
  • Parse.Promise用你的库周围的包装器覆盖。

第二种似乎更高效、更稳定,更易于维护,因为在 Parse 更改其 API 时不需要调整。

Parse.Promise = (function(oldPromise, Promise) {
    function promise() {
        var res, rej;
        var p = new Promise(function(_res, _rej) {
            res = _res;
            rej = _rej;
        });
        p.resolve = res;
        p.reject = rej;
        return p;
    }
    promise.is = oldPromise.is;
    promise.as = Promise.resolve;
    promise.error = Promise.reject;
    promise.when = Promise.all; // ²
    promise._continueWhile = oldPromise._continueWhile;
    Promise.prototype._continueWith = oldPromise.prototype._continueWith;
    Promise.prototype._thenRunCallback = oldPromise.prototype._thenRunCallback;

    // you might not need / want these ³
    Promise.prototype.always = oldPromise.prototype.always;
    Promise.prototype.done = oldPromise.prototype.done; 
    Promise.prototype.fail = oldPromise.prototype.fail;

    return promise;
}(Parse.Promise, require("Bluebird"))); // or whatever

2:Promise.all解析为数组,同时Parse.Promise.when使用多个参数解析(见下文)。您可能希望/需要保留它并promise.when = oldPromise.when;改为使用。
3:确保不要在此处覆盖自定义库的方法。Parse 不需要这些方法,它们是为了与 jQuery 兼容。

请注意,Parse 确实像 jQuery 一样,有时会使用多个值解析它的 Promise,例如在Parse._ajax. 它在内部不依赖此功能,但您应该检查您最喜欢的 Promise 库如何处理它们。

于 2015-07-04T17:11:49.653 回答
3

一种选择是修改 Parse SDK 原型以返回不同类型的 Promise。

一个很好的起点是这个库https://github.com/brandid/parse-angular-patch/blob/master/src/parse-angular.js它修补 Parse 原型以返回 AngularJS 承诺

            // Keep a handy local reference
            var Parse = $window.Parse;

            //-------------------------------------
            // Structured object of what we need to update
            //-------------------------------------

            var methodsToUpdate = {
                "Object": {
                    prototype: ['save', 'fetch', 'destroy'],
                    static: ['saveAll', 'destroyAll']
                },
                "Collection": {
                    prototype: ['fetch'],
                    static: []
                },
                "Query": {
                    prototype: ['find', 'first', 'count', 'get'],
                    static: []
                },
                "Cloud": {
                    prototype: [],
                    static: ['run']
                },
                "User": {
                    prototype: ['signUp'],
                    static: ['requestPasswordReset', 'logIn']
                },
                "FacebookUtils": {
                    prototype: [],
                    static: ['logIn', 'link', 'unlink']
                },
                "Config": {
                    prototype: [],
                    static: ['get']
                }
            };

            //// Let's loop over Parse objects
            for (var k in methodsToUpdate) {

                var currentClass = k;
                var currentObject = methodsToUpdate[k];

                var currentProtoMethods = currentObject.prototype;
                var currentStaticMethods = currentObject.static;


                /// Patching prototypes
                currentProtoMethods.forEach(function(method){

                    var origMethod = Parse[currentClass].prototype[method];

                    // Overwrite original function by wrapping it with $q
                    Parse[currentClass].prototype[method] = function() {

                        return origMethod.apply(this, arguments)
                        .then(function(data){
                            var defer = $q.defer();
                            defer.resolve(data);
                            return defer.promise;
                        }, function(err){
                            var defer = $q.defer();
                            defer.reject(err);
                            return defer.promise;
                        });


                    };

                });


                ///Patching static methods too
                currentStaticMethods.forEach(function(method){

                    var origMethod = Parse[currentClass][method];

                    // Overwrite original function by wrapping it with $q
                    Parse[currentClass][method] = function() {

                        return origMethod.apply(this, arguments)
                        .then(function(data){
                            var defer = $q.defer();
                            defer.resolve(data);
                            return defer.promise;
                        }, function(err){
                            var defer = $q.defer();
                            defer.reject(err);
                            return defer.promise;
                        });

                    };

                });


            }
于 2015-07-02T09:41:04.747 回答