5

受到在 javascript 中使用 Promises 的这个(优秀)讨论的启发,我试图弄清楚如何使用 Deferred 将异步和非异步函数链接在一起,以避免在使用我的“全局存储”代码时支付回调税。

我有几个与此相关的问题,但我会在这里一起问,因为上下文是相同的。

我无法解决的一件事是如何从非异步的东西中创建一个 deferred - 也就是说,我如何获取一个值,将其包装在一个 Promise 中,然后直接返回它?( a -> M<a>)

另外,我怎样才能获取一个异步函数并将其包装,以便它直接返回其结果,但包装在一个承诺中?( (a -> b) -> (a -> M<b>))

最后一个问题,对于 monadic 怪胎 - 这个函数有标准名称吗?[a] -> (a -> M<b>) -> M<[b]>

4

3 回答 3

5

将值包装到 Promise 中就像使用 $.when 一样简单:

var promise = $.when( value );

此外,从 jQuery 1.6 开始,您有一个非常简单的链接方法(管道):

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

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

希望这可以帮助。

于 2011-08-23T00:53:51.723 回答
1

在@Pointy 的帮助下,实现“提升”变得微不足道:

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 返回一个新函数,该函数接受一个值数组,并使用它们返回延迟项内的另一个值列表。

于 2011-04-06T17:23:45.920 回答
1

认为你将一个值变成一个 Promise 的方式就是“预先成功”Deferred:

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

现在将一个函数传递给“.do​​ne()”将导致该函数立即被调用该值。

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

会立即提醒“你好”。

于 2011-04-06T16:45:10.240 回答