使用Promises设计模式,是否可以实现以下内容:
var a, promise
if promise.resolve
a = promise.responsevalue;
if promise.reject
a = "failed"
AFTER resolution/rejection. Not ASYNC!!
send a somewhere, but not asynchronously. //Not a promise
在[{1}}情况下,我所寻找的内容与finally
类似。
PS:我在NodeJS上使用ES6 Promise polyfill
答案 0 :(得分:13)
如果您从catch
返回值,则可以then
使用catch
。
thePromise.then(result => doSomething(result)
.catch(error => handleErrorAndReturnSomething(error))
.then(resultOrReturnFromCatch => /* ... */);
...但这意味着您将拒绝转换为解决方案(通过从catch
返回内容而不是抛弃或返回被拒绝的承诺),并依赖于此事实。
如果你想要一些透明地传递分辨率/拒绝而不修改它的东西,那么ES2015(" ES6")承诺没有内置任何东西可以做到这一点,但它很容易写(这是在ES2015,但我在下面有一个ES5翻译):
{
let worker = (p, f, done) => {
return p.constructor.resolve(f()).then(done, done);
};
Object.defineProperty(Promise.prototype, "finally", {
value(f) {
return this.then(
result => worker(this, f, () => result),
error => worker(this, f, () => { throw error; })
);
}
});
}
示例:
{
let worker = (p, f, done) => {
return p.constructor.resolve(f()).then(done, done);
};
Object.defineProperty(Promise.prototype, "finally", {
value(f) {
return this.then(
result => worker(this, f, () => result),
error => worker(this, f, () => { throw error; })
);
}
});
}
test("p1", Promise.resolve("good")).finally(
() => {
test("p2", Promise.reject("bad"));
}
);
function test(name, p) {
return p.then(
result => {
console.log(name, "initial resolution:", result);
return result;
},
error => {
console.log(name, "initial rejection; propagating it");
throw error;
}
)
.finally(() => {
console.log(name, "in finally");
})
.then(
result => {
console.log(name, "resolved:", result);
},
error => {
console.log(name, "rejected:", error);
}
);
}

关于这一点的几点说明:
请注意this.constructor
的使用,以便我们在任何类型的承诺(包括可能的子类)上创建原始承诺时调用resolve
;这与Promise.resolve
和其他人的工作方式一致,是支持子类承诺的重要部分。
上述故意不包括finally
回调的任何参数,并且没有表明承诺是否得到解决或拒绝,以便与{{ 1}}在经典的finally
结构中。但如果有人想要,可以轻松地将一些信息传递给回调。
同样,以上内容不使用try-catch-finally
回调返回的值,除非,如果它是承诺,它会在允许之前等待承诺结算链条继续。
这是ES5的翻译:
finally
示例:
(function() {
function worker(ctor, f, done) {
return ctor.resolve(f()).then(done, done);
}
Object.defineProperty(Promise.prototype, "finally", {
value: function(f) {
var ctor = this.constructor;
return this.then(
function(result) {
return worker(ctor, f, function() {
return result;
});
},
function(error) {
return worker(ctor, f, function() {
throw error;
});
}
);
}
});
})();

我认为这是将此功能集成到ES5中的Promise polyfill中的最简单方法。
或者,如果您更喜欢子类(function() {
function worker(ctor, f, done) {
return ctor.resolve(f()).then(done, done);
}
Object.defineProperty(Promise.prototype, "finally", {
value: function(f) {
var ctor = this.constructor;
return this.then(
function(result) {
return worker(ctor, f, function() {
return result;
});
},
function(error) {
return worker(ctor, f, function() {
throw error;
});
}
);
}
});
})();
test("p1", Promise.resolve("good")).finally(function() {
test("p2", Promise.reject("bad"));
});
function test(name, p) {
return p.then(
function(result) {
console.log(name, "initial resolution:", result);
return result;
},
function(error) {
console.log(name, "initial rejection; propagating it");
throw error;
}
)
.finally(function() {
console.log(name, "in finally");
})
.then(
function(result) {
console.log(name, "resolved:", result);
},
function(error) {
console.log(name, "rejected:", error);
}
);
}
而不是修改其原型:
Promise
示例:
let PromiseX = (() => {
let worker = (p, f, done) => {
return p.constructor.resolve(f()).then(done, done);
};
class PromiseX extends Promise {
finally(f) {
return this.then(
result => worker(this, f, () => result),
error => worker(this, f, () => { throw error; })
);
}
}
PromiseX.resolve = Promise.resolve;
PromiseX.reject = Promise.reject;
return PromiseX;
})();

您已经说过要在不延长let PromiseX = (() => {
let worker = (p, f, done) => {
return p.constructor.resolve(f()).then(done, done);
};
class PromiseX extends Promise {
finally(f) {
return this.then(
result => worker(this, f, () => result),
error => worker(this, f, () => { throw error; })
);
}
}
PromiseX.resolve = Promise.resolve;
PromiseX.reject = Promise.reject;
return PromiseX;
})();
test("p1", PromiseX.resolve("good")).finally(
() => {
test("p2", PromiseX.reject("bad"));
}
);
function test(name, p) {
return p.then(
result => {
console.log(name, "initial resolution:", result);
return result;
},
error => {
console.log(name, "initial rejection; propagating it");
throw error;
}
)
.finally(() => {
console.log(name, "in finally");
})
.then(
result => {
console.log(name, "resolved:", result);
},
error => {
console.log(name, "rejected:", error);
}
);
}
或子类的情况下执行此操作。在ES5中,效用函数非常难以使用,因为您必须将承诺传递给它,这与正常的承诺使用完全不一致。在ES2015中,可以做一些更自然的事情,但是调用它比修改原型或子类化更令人痛苦:
Promise.prototype
用法:
let always = (() => {
let worker = (f, done) => {
return Promise.resolve(f()).then(done, done);
};
return function always(f) {
return [
result => worker(f, () => result),
error => worker(f, () => { throw error; })
];
}
})();
注意使用扩展运算符(这就是为什么它不能在ES5中工作),因此thePromise.then(...always(/*..your function..*/)).
可以为always
提供两个参数。
示例:
then

在评论中,您表示担心let always = (() => {
let worker = (f, done) => {
return Promise.resolve(f()).then(done, done);
};
return function always(f) {
return [
result => worker(f, () => result),
error => worker(f, () => { throw error; })
];
}
})();
test("p1", Promise.resolve("good")).then(...always(
() => {
test("p2", Promise.reject("bad"));
}
));
function test(name, p) {
return p.then(
result => {
console.log(name, "initial resolution:", result);
return result;
},
error => {
console.log(name, "initial rejection; propagating it");
throw error;
}
)
.then(...always(() => {
console.log(name, "in finally");
}))
.then(
result => {
console.log(name, "resolved:", result);
},
error => {
console.log(name, "rejected:", error);
}
);
}
不会等待承诺;这是最后一个finally
示例,延迟证明它确实如此:
always

答案 1 :(得分:3)
ES2015代码:
promise.then(val => val).catch(() => "failed").then(a => doSomethigWithA(a));