我有一个对象(foo
),它将几个方法公开为promises(使用JQuery延迟)。我这样做的方式最终得到了这种代码:
var foo = createNewFoo();
$.when(foo.method1(arg))
.then(foo.method2)
.then(foo.method3);
我希望将代码重构为更好的代码,例如:
var foo = createNewFoo()
.method1(arg)
.method2()
.method3();
但我不确定如何实施foo
以便这样做。
答案 0 :(得分:2)
是的,您只需要扩展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
我不确定它是否值得,但它确实有效。
答案 1 :(得分:1)
您需要使用所需的方法返回自定义对象,并让它直接承诺状态而不是状态作为属性。在每个方法中,您需要在包装的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概述的方法,但实施起来要简单得多。
答案 2 :(得分:0)
我并没有真正意识到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
答案 3 :(得分:0)
创建自己的承诺。
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(/*...*/);
}
}