链接承诺而不使用“then”

Chaining promises without using 'then'

本文关键字:then 承诺 链接      更新时间:2023-09-26

我有一个对象(foo),它将几个方法公开为承诺(使用jQuery deferred)。我这样做的方式最终得到了这种代码:

var foo = createNewFoo();
$.when(foo.method1(arg))
    .then(foo.method2)
    .then(foo.method3);

我希望重构下面的代码更好,看起来像这样:

var foo = createNewFoo()
    .method1(arg)
    .method2()
    .method3();

但我不确定如何实现foo这是可能的。

是的,当然,您只需要扩展Deferred即可使用这些方法:

function MyRpc { // if you can use ES2015 - this should be a `class`
  this._deferred = new $.Deferred();
}
// teach it to be a promise
MyRpc.prototype.then = function(onFulfilled, onRejected) {
  return this._deferred.then(onFulfilled, onRejected);
};
// teach it to be a deferred
MyRpc.protototype.resolve = function(arg) {
  this._deferred.resolve(arg);
};
MyRpc.prototype.reject = function(arg) {
  this._deferred.reject(arg);
};
// define your methods!
MyRpc.prototype.method1 = function(arg) {
  var p = this._deferred.then(function(value) {
    // logic of `method1` from foo.method1 here
  });
  var rpc = new MyRpc(); // our continuation;
  p.then(function(v) { rpc.resolve(v) }, function(e) { rpc.reject(e); });
  return rpc;
};

当然,使用真正的 promise 库,这一切都比使用 jQuery 的最小 promise 要容易得多

这将允许您执行以下操作:

var rpc = new MyRpc();
rpc.method1(1).method1(2).method1(3); // can also `.then` here

我不确定这是否值得,但它有效。

您需要返回一个包含所需方法的自定义对象,并让它直接将状态而不是状态作为属性。在每个方法中,都需要对包装的承诺调用then,并返回另一个实例,该实例为新状态(方法结果)包装新承诺。

function Foo(promise) {
    // make every instance a thenable:
    this.then = promise.then.bind(promise);
    // alternatively store the promise itself as a property and always call this.promise.then
}
function createNewFoo() {
    return new Foo($.when({/* initial state */}));
}
Foo.prototype.method1 = function method1(args) {
    return new Foo(this.then(function(curstate) {
        // method logic here
        // should `return` a new state - or a promise for it
    });
};
Foo.prototype.method2 = …;

这类似于Benjamin Gruenbaum和Louy概述的方法,但实现起来要简单得多。

我真的不知道承诺(所以如果有一些实现错误,请原谅我的例子),但这可以使用 ES6 Proxy .

目前,它仅在最新的浏览器上可用,因此可能无法满足您的要求。

代理允许在每个对象操作上添加一个回调函数,这意味着您可以检索被调用方法的名称来执行您想要的操作。在您的情况下,您希望使用第一个 promise 调用 $.when(),并使用其他人调用 .then() 作为参数。

"use strict";
function createNewFoo(){
    let foo = new Foo();
    let proxy = new Proxy(foo, {
        // @param target : Object on which the operation will be made
        // @param name : property name
        get(target, name) {
            let promise = target[name];
            return function (...args) {
                if (typeof promise === "function"){
                    promise = promise.apply(target, args);
                }
                else if (!(promise instanceof Promise)){
                    throw 'Can''t handle "'+name+'"';
                }
                // Perform chaining
                if (!target.promise){
                    target.promise = $.when(promise);
                }
                else{
                    target.promise.then(promise);
                }
                return proxy;
            };
        }
    });
    // Storing the Foo instance in the Proxy object, could be implemented in other way.
    proxy._target = foo;
    return proxy;
}

假设您使用的是定义为波纹管的"类"

function Foo(){
    // storing the promise result
    this.promise = null;
    this.method1 = function(arg){ 
        return new Promise(function(resolve, reject) {
            resolve("1");
        }); 
    }
    this.method2 = new Promise(function(resolve, reject) {
        resolve("2");
    });
    this.method3 = new Promise(function(resolve, reject) {
        resolve("3");
    });
}

您现在可以使用这段代码来链接您的承诺

var fooProxy = createNewFoo()
    .method1(1)
    .method2()
    .method3();

并检索原始 Foo 实例

fooProxy._target 

创建自己的承诺。

function MyPromise(resolver) {
  var _promise = new Promise(resolver);
  this.then = function(onFulfilled, onRejected) {
    var _p = _promise.then(onFulfilled, onRejected);
    return new MyPromise(_p.then.bind(_p));
  };
}

添加您想要的任何方法...

MyPromise.prototype.doSomething = function() {
  return this.then(/*...*/);
};

瞧!

new MyPromise()
  .then(/*...*/).doSomething()
  .then(/*...*/).doSomething(); // etc...

奖金:

['resolve', 'reject', 'all'].forEach(function(method) {
  MyPromise[method] = function(...args) {
    var promise = Promise[method](...args);
    return new MyPromise(promise.then.bind(promise));
  };
});

同样在 ES6 中:

class MyPromise {
  constructor(resolver) {
    var _promise = new Promise(resolver);
    this.then = function(onFulfilled, onRejected) {
      var _p = _promise.then(onFulfilled, onRejected);
      return new MyPromise(_p.then.bind(_p));
    };
  }
  doSomething() {
    return this.then(/*...*/);
  }
}