【问题标题】:Can I use other promise implementations in the Parse JavaScript SDK?我可以在 Parse JavaScript SDK 中使用其他的 Promise 实现吗?
【发布时间】:2015-09-02 23:59:49
【问题描述】:

我很担心我看到的 Parse 使用 JQuery 兼容的 Promise 的引用,因为我读过 jQuery Promise allow consumers to mutate the state of the promise。是否可以将已知与 Promises/A+ 兼容的另一个 Promise 实现(例如 ECMAScript 6 implementationBluebird)与 Parse JavaScript SDK 一起使用?

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

注意这个问题是Parse Developers group 上的originally asked,但没有收到任何回复。

【问题讨论】:

  • 我很乐意为您提供帮助,但不幸的是,我认为唯一能回答是否支持其他实现的问题的人是 Parse 的程序员。
  • "jQuery promises 允许消费者改变 promises 的状态" - 这个错误已经在 jQuery 1.8 - 3 年前修复了!
  • 您是在寻找返回自定义实现承诺的 Parse 库方法,还是只是想在 Parse 环境中导入任意库?
  • @Bergi:Parse 库没有使用 jQuery 的 promise 实现——它使用了自己的自定义 promise 实现,这是我不信任的。我正在寻找一种方法让图书馆返回任何已知符合 Promises/A+ 的内容:它不必是我选择的图书馆,我只想知道我得到的承诺无需审核 Parse 的代码即可按预期运行。
  • @JasonWhittle:解析承诺 do 的行为与预期的 afaik 一样。在此之前,它们仍然是有效的 A+ thenable,可以被您选择的 Promise 实现所吸收。

标签: javascript parse-platform promise bluebird es6-promise


【解决方案1】:

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

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

1:通过公共方法。因此,不会比大多数其他实现更多。

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

是的。 Parse SDK 确实返回有效的 A+ thenables,这意味着您可以从您最喜欢的 Promise 实现的 then 回调中返回 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 的实现将属性 _isPromisesAPlusCompliant 定义为 false,然后在图书馆。

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

Parse.Promise._isPromisesAPlusCompliant = true;

更新:在较新的版本中,这不会暴露为带下划线的属性,而是您必须调用(未记录的)Parse.Promise.enableAPlusCompliant() 方法。详情见issue #57

我查看了the code,这个标志基本上改变了 3 件事:

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

这些确实解决了当前时间的problems inherent to the jQuery Deferred implementation

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

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

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

  • 通过使用Promise.resolve 组合来装饰API 中的所有返回承诺的方法,这基本上是@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 库如何处理它们。

【讨论】:

  • “我假设 Parse 计划默默地迁移这个真实设置以成为默认设置”:确实是这样,参见。 github.com/ParsePlatform/Parse-SDK-JS/issues/57
  • @LaneRettig:感谢您的确认 :-)
  • 你应该如何require这个sn-p代码?它说 Parse 没有定义...
  • @fatuhoku:这取决于您的环境(节点等)。代码只希望在第一个参数中获取 Parse.Promise 对象,在第二个参数中获取替换库的构造函数。
【解决方案2】:

一种选择是修改 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;
                        });

                    };

                });


            }

【讨论】:

【解决方案3】:

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

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

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

【讨论】:

    猜你喜欢
    • 2017-12-01
    • 2013-11-16
    • 1970-01-01
    • 2011-07-11
    • 1970-01-01
    • 2021-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多