链接承诺而不使用’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(/*...*/); } }