链接承诺而不使用’then’

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

 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的最小承诺容易得多。

这可以让你做到:

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

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

您将需要使用所需的方法返回自定义对象,并让它直接承诺状态而不是状态作为属性。 在每个方法中,您都需要在包装的promise上调用, 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概述的方法,但实施起来要简单得多。

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

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

代理允许在每个对象操作上添加回调函数,这意味着您可以检索被调用方法的名称以执行您想要的操作。 在您的情况下,您希望使用第一个承诺调用$.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(/*...*/); } }