Заклинание JQuery, отсроченного монадическими заклинаниями - PullRequest
5 голосов
/ 06 апреля 2011

Вдохновленный этим (превосходным) обсуждением использования Promises в javascript, я пытаюсь выяснить, как можно использовать Deferred для объединения вместе асинхронных и неасинхронных функций, чтобы избежать уплаты налога на обратный вызовпри использовании моего кода ' Global storage '.

У меня есть несколько вопросов, связанных с этим, но я задам их здесь вместе, потому что контекст один и тот же.

Одна вещь, которую я не могу понять, это то, как я могу сделать отложенное из чего-то, что не является асинхронным, то есть, как я могу взять значение, обернуть его в обещание и вернуть его напрямую?(a -> M<a>)

Кроме того, как я могу взять асинхронную функцию и обернуть ее так, чтобы она возвращала свой результат напрямую, но в виде обещания?((a -> b) -> (a -> M<b>))

Последний вопрос для монадических уродов - есть ли стандартное название для этой функции?[a] -> (a -> M<b>) -> M<[b]>

Ответы [ 3 ]

5 голосов
/ 23 августа 2011

Заключить значение в обещание так же просто, как использовать $ .when:

var promise = $.when( value );

Кроме того, начиная с jQuery 1.6, у вас есть очень простой метод связывания (pipe):

var chained = functionThatReturnsAPromise().pipe(function( resolveValue ) {
        return functionThatReturnsAnotherPromise( resolveValue );
    });

chained.done(function() {
    // Both asynchronous operations done in sequence
});

Надеюсь, это поможет.

1 голос
/ 06 апреля 2011

При поддержке @Pointy реализация 'lift' становится тривиальной:

function unit(value) {
  var rv = $.Deferred();
  rv.resolveWith(null, [value]);
  return rv.promise();
}
function lift(fn) {
  return function(x) {
    return unit(fn(x));
  };
}
lift(alert)("hello");

function bind(fn) {
   return function(x) {
     return x.done(function(y) { return fn(y); });
   }
}

function compose(f, g) { return function(x) { g(f(x)); } };
function twice(x) { return 2 * x; }
var alert2 = compose(bind(lift(twice)), bind(lift(alert)));

alert2(unit(4)); //error at the end because alert doesn't return any values

Теперь мне осталось только разобраться, как реализовать [a] -> (a -> M<b>) -> M<[b]> и как это назвать!

РЕДАКТИРОВАТЬ , вместо этого я реализовал (a -> M<b>) -> ([a] -> M<[b]>), это выглядит так:

function listBind(fn) {
    return function(a) {        
      var Mb = $.Deferred();
      var b = [], pending = a.length;
      var callback = function(i,val) {
         b[i] = val;
         if(--pending == 0) Mb.resolve(b);
      };
      for(var i = 0, n = a.length; i < n; i++) {
          (function(closure) { //ugly, but have to use closure to 'copy' i
             fn(a[closure]).done(function(val) { callback(closure, val); })
          })(i);
      }
      return Mb.promise();
    };
}

Итак, для функции, которая получает один отложенный элемент, эта функция listBind возвращает новую функцию, которая принимает массив значений и использует их для возврата другого списка значений внутри отложенного элемента.

1 голос
/ 06 апреля 2011

Я думаю способ, которым вы бы превратили значение в Обещание, состоит в том, чтобы просто "преуспеть" в Отложенном:

function v2p(value) {
  var rv = $.Deferred();
  rv.resolveWith(null, [value]);
  return rv.promise();
}

Теперь передача функции в ".done ()" приведет к немедленному вызову функции со значением.

v2p("hello").done(function(value) { alert(value); });

немедленно предупредит "привет".

...