nik*_*ohn 16 javascript asynchronous promise chain
使用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
Run Code Online (Sandbox Code Playgroud)
我正在寻找的是类似finally的try - catch情况.
PS:我在NodeJS上使用ES6 Promise polyfill
T.J*_*der 15
如果从中返回值catch,则可以使用then结果catch.
thePromise.then(result => doSomething(result)
.catch(error => handleErrorAndReturnSomething(error))
.then(resultOrReturnFromCatch => /* ... */);
Run Code Online (Sandbox Code Playgroud)
......但这意味着你将拒绝转化为解决方案(通过返回某些内容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; })
);
}
});
}
Run Code Online (Sandbox Code Playgroud)
例:
{
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);
}
);
}Run Code Online (Sandbox Code Playgroud)
关于这一点的几点说明:
注意使用,this.constructor以便我们调用resolve任何类型的promise(包括可能的子类)创建原始的promise; 这Promise.resolve与其他人的工作方式一致,是支持子类承诺的重要组成部分.
以上是故意不包括finally回调的任何参数,并且没有表明承诺是否被解决或拒绝,以便与finally经典try-catch-finally结构保持一致.但如果有人想要,可以轻松地将一些信息传递给回调.
同样的,上面没有使用由返回值finally的回调只是,如果它是一个承诺,它等待的承诺,允许链继续前解决.
这是ES5的翻译:
(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;
});
}
);
}
});
})();
Run Code Online (Sandbox Code Playgroud)
例:
(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);
}
);
}Run Code Online (Sandbox Code Playgroud)
我认为这是将此功能集成到ES5中的Promise polyfill中的最简单方法.
或者如果您更喜欢子类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;
})();
Run Code Online (Sandbox Code Playgroud)
例:
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);
}
);
}Run Code Online (Sandbox Code Playgroud)
你已经说过要在没有扩展Promise.prototype 或子类化的情况下做到这一点.在ES5中,实用程序功能使用起来非常笨拙,因为你必须将它作为承诺传递给它,这与正常的承诺使用完全不同步.在ES2015中,可以做一些更自然的事情,但是调用还是比修改原型或子类更难:
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; })
];
}
})();
Run Code Online (Sandbox Code Playgroud)
用法:
thePromise.then(...always(/*..your function..*/)).
Run Code Online (Sandbox Code Playgroud)
注意使用扩展运算符(这就是为什么这在ES5中不起作用),因此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);
}
);
}Run Code Online (Sandbox Code Playgroud)
在评论中,你表示担心finally不会等待承诺; 这是最后一个always例子,延迟证明它确实:
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", 500, false, "good").then(...always(
() => {
test("p2", 500, true, "bad");
}
));
function test(name, delay, fail, value) {
// Make our test promise
let p = new Promise((resolve, reject) => {
console.log(name, `created with ${delay}ms delay before settling`);
setTimeout(() => {
if (fail) {
console.log(name, "rejecting");
reject(value);
} else {
console.log(name, "resolving");
resolve(value);
}
}, delay);
});
// Use it
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);
}
);
}Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9755 次 |
| 最近记录: |