Подтвердить что ты не робот

Могу ли я использовать другие реализации обещаний в Parse JavaScript SDK?

Я беспокоюсь о ссылках, которые я видел в Parse, используя JQuery-совместимый promises, поскольку я прочитал, что jQuery promises позволяет потребителям мутировать состояние обещания. Возможно ли использовать другую реализацию обещания, которая, как известно, соответствует Promises/A + (например, ECMAScript 6 реализация или Bluebird) с помощью Parse JavaScript SDK?

Обычно я предполагаю, что это невозможно, но в версии 1.4.2 из Parse JavaScript SDK реализация Parse.Promise определяет свойство "_isPromisesAPlusCompliant" как false, которое затем проверяется в различных функциях в библиотеке.

N.B. Этот вопрос был изначально задан в группе Parse Developers, но не получил ответов.

4b9b3361

Ответ 1

Я обеспокоен тем, что Parse использует jQuery-совместимый promises, поскольку я прочитал, что jQuery promises позволяет потребителям изменять состояние обещания.

Вам не нужно беспокоиться. "jQuery-совместимый" может означать много вещей, а Parse promises, безусловно, не позволяет потребителям изменять свое состояние 1 (поскольку jQuery не выполняется ни с годами). Btw, они тоже "совместимы": -)

1: через общедоступные методы. Таким образом, не больше, чем большинство других реализаций.

Можно ли использовать другую реализацию обещания, которая, как известно, является Promises/A +, совместимой с пакетом JavaScript для парсинга?

Да. Parse SDK действительно возвращает действительные A + thenables, что означает, что вы можете возвращать ответные действия Parse promises из then вашей любимой реализации обещания и ожидать, что он будет работать безупречно:

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

Вы также можете включить их в действительный promises своей реализации, используя Promise.resolve, например:

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

Обычно я предполагаю, что это невозможно, но в v1.4.2 из Parse JavaScript SDK реализация Parse.Promise определяет свойство _isPromisesAPlusCompliant как false, которое затем проверяется в различных функциях в библиотеке.

Он! Хотя это, к сожалению, недокументировано, этот флаг действительно позволяет вам сделать собственную библиотеку обещаний Parse.com A + совместимой в вашем приложении:

Parse.Promise._isPromisesAPlusCompliant = true;

Обновление. В более новых версиях это не отображается как свойство underscored, но вам нужно вызвать метод (недокументированный) Parse.Promise.enableAPlusCompliant(). Подробнее см. issue # 57.

Я просмотрел код, и этот флаг в основном изменяет 3 вещи:

  • Исключения в then обратные вызовы пойманы и приводят к отказу от обещания результата вместо глобальной ошибки. Таким образом, вы можете использовать throw в них.
  • Если вы return значение от обратного вызова onRejected (второй параметр до then), предполагается, что ошибка будет обработана, а обещание результата будет выполнено вместо отклонения.
  • Все обратные вызовы then выполняются асинхронно.

Это действительно решение именно проблем, присущих реализации jQuery Deferred в настоящее время.

Я предполагаю, что Parse планируют бесшумно перенести этот параметр true, чтобы стать стандартным, и тестируют, что он сломает что-либо для пользователей. Я предполагаю, что это довольно безопасно использовать, даже если не документировано.

Я хочу, чтобы все API-интерфейсы Parse вернули promises моей пользовательской библиотеки.

Это не так просто, хотя это можно сделать. Существуют в основном два подхода:

  • украсить все методы, возвращающие обещания в API, составив их с помощью Promise.resolve, что в основном означает, что @danamper предложил
  • перезапись 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, иногда разрешает его promises с несколькими значениями, например. в Parse._ajax. Он не полагается на эту функцию внутри, но вы должны проверить, как справляется ваша любимая библиотека обещаний.

Ответ 2

Вы можете использовать собственный Promises или хороший polyfill. Вы можете инкапсулировать любой последующий (объект, подобный обещанию, с помощью метода public, а затем метод) в вызове Promise.resolve, например:

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

Это также будет иметь метод then, но без головных болей. Он должен работать.

Ответ 3

Один из вариантов - изменить прототипы Parse SDK, чтобы вернуть другой тип Promise.

Хорошей отправной точкой является эта библиотека https://github.com/brandid/parse-angular-patch/blob/master/src/parse-angular.js, которая исправляет прототипы Parse, чтобы вернуть AngularJS promises

            // 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 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;
                        });

                    };

                });


            }