我一直在使用ES6 Promise。
通常,Promise是这样构造和使用的
new Promise(function(resolve, reject){
if (someCondition){
resolve();
} else {
reject();
}
});
但我一直在做下面这样的事情,为了灵活起见,把决心放在外面。
var outsideResolve;
var outsideReject;
new Promise(function(resolve, reject) {
outsideResolve = resolve;
outsideReject = reject;
});
后来
onClick = function(){
outsideResolve();
}
这很好,但是否有更简单的方法来做到这一点?如果不是,这是一个好的实践吗?
因为我没有找到我想要的东西,所以当我以这个问题结束时,我将分享我真正想要实现的东西。
场景:我有3个不同的API,具有相同的可能响应,因此我想在一个函数中处理承诺的完成和错误处理。这就是我所做的:
创建一个处理器函数:
private handleHttpPromise = (promise: Promise<any>) => {
promise
.then((response: any) => {
// do something with the response
console.log(response);
})
.catch((error) => {
// do something with the error
console.log(error);
});
};
将承诺发送给创建的处理程序
switch (method) {
case 'get': {
this.handleHttpPromise(apiService.get(url));
break;
}
case 'post': {
if (jsonData) {
this.handleHttpPromise(apiService.post(url, jsonData));
}
break;
}
// (...)
}
我为此写了一个小库。https://www.npmjs.com/package/@inf3rno/promise.exposed
我使用了别人写的工厂方法,但是我也重写了then, catch, finally方法,所以你也可以通过这些方法解决原来的承诺。
在没有外部执行人的情况下解决承诺:
const promise = Promise.exposed().then(console.log);
promise.resolve("This should show up in the console.");
从外部与执行器的setTimeout赛跑:
const promise = Promise.exposed(function (resolve, reject){
setTimeout(function (){
resolve("I almost fell asleep.")
}, 100000);
}).then(console.log);
setTimeout(function (){
promise.resolve("I don't want to wait that much.");
}, 100);
如果你不想污染全局命名空间,有一个无冲突模式:
const createExposedPromise = require("@inf3rno/promise.exposed/noConflict");
const promise = createExposedPromise().then(console.log);
promise.resolve("This should show up in the console.");
helper方法可以减轻这种额外的开销,并给您同样的jQuery感觉。
function Deferred() {
let resolve;
let reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
}
用法是
const { promise, resolve, reject } = Deferred();
displayConfirmationDialog({
confirm: resolve,
cancel: reject
});
return promise;
它类似于jQuery
const dfd = $.Deferred();
displayConfirmationDialog({
confirm: dfd.resolve,
cancel: dfd.reject
});
return dfd.promise();
不过,在用例中,这种简单的本机语法就可以了
return new Promise((resolve, reject) => {
displayConfirmationDialog({
confirm: resolve,
cancel: reject
});
});
我喜欢@JonJaques的回答,但我想更进一步。
如果你绑定并捕获Deferred对象,那么它完全实现了Promise API,你可以将它视为Promise并等待它等等。
⚠️ Editor's Note: I don't recommend this kind of pattern anymore since at the time of writing, Promise.prototype.finally was not a thing yet, then it became a thing… This could happen to other methods so I recommend you augment the promise instance with resolve and reject functions instead:
function createDeferredPromise() {
let resolve
let reject
const promise = new Promise((thisResolve, thisReject) => {
resolve = thisResolve
reject = thisReject
})
return Object.assign(promise, {resolve, reject})
}
Go upvote someone else's answer.
class DeferredPromise {
constructor() {
this._promise = new Promise((resolve, reject) => {
// assign the resolve and reject functions to `this`
// making them usable on the class instance
this.resolve = resolve;
this.reject = reject;
});
// bind `then` and `catch` to implement the same interface as Promise
this.then = this._promise.then.bind(this._promise);
this.catch = this._promise.catch.bind(this._promise);
this.finally = this._promise.finally.bind(this._promise);
this[Symbol.toStringTag] = 'Promise';
}
}
const deferred = new DeferredPromise();
console.log('waiting 2 seconds...');
setTimeout(() => {
deferred.resolve('whoa!');
}, 2000);
async function someAsyncFunction() {
const value = await deferred;
console.log(value);
}
someAsyncFunction();