我有一个纯JavaScript承诺(内置实现或poly-fill):
var promise = new promise(函数(解析,拒绝){/*…* /});
从规范来看,Promise可以是:
" settle "和" resolved "
“解决”和“拒绝”
“等待”
我有一个用例,我希望同步审问承诺并确定:
承诺达成了吗?
如果是,承诺解决了吗?
我知道我可以使用#then()来安排在Promise改变状态后异步执行的工作。我不是在问你该怎么做。
这个问题是关于Promise状态的同步询问。我怎样才能做到这一点呢?
你可以在Promise.prototype中添加一个方法。它是这样的:
编辑:第一个解决方案不能正常工作,就像这里的大多数答案一样。它返回“pending”直到异步函数“。然后”被调用,这不是立即发生的。(使用Promise.race的解决方案也是如此)。我的第二个解决方案解决了这个问题。
if (window.Promise) {
Promise.prototype.getState = function () {
if (!this.state) {
this.state = "pending";
var that = this;
this.then(
function (v) {
that.state = "resolved";
return v;
},
function (e) {
that.state = "rejected";
return e;
});
}
return this.state;
};
}
你可以在任何承诺上使用它。为例:
myPromise = new Promise(myFunction);
console.log(myPromise.getState()); // pending|resolved|rejected
第二个(也是正确的)解决方案:
if (window.Promise) {
Promise.stateable = function (func) {
var state = "pending";
var pending = true;
var newPromise = new Promise(wrapper);
newPromise.state = state;
return newPromise;
function wrapper(resolve, reject) {
func(res, rej);
function res(e) {
resolve(e);
if (pending) {
if (newPromise)
newPromise.state = "resolved";
else
state = "resolved";
pending = false;
}
}
function rej(e) {
reject(e);
if (pending) {
if (newPromise)
newPromise.state = "rejected";
else
state = "rejected";
pending = false;
}
}
}
};
}
并使用它:
注意:在这个解决方案中,您不必使用“new”操作符。
myPromise = Promise.stateable(myFunction);
console.log(myPromise.state); // pending|resolved|rejected
这里是一个更充实的QueryablePromise的es6版本,允许在第一次解析后进行链接和捕获,并立即解析或拒绝以保持api与本机Promise一致。
const PROMISE = Symbol('PROMISE')
const tap = fn => x => (fn(x), x)
const trace = label => tap(x => console.log(label, x))
class QueryablePromise {
resolved = false
rejected = false
fulfilled = false
catchFns = []
constructor(fn) {
this[PROMISE] = new Promise(fn)
.then(tap(() => {
this.fulfilled = true
this.resolved = true
}))
.catch(x => {
this.fulfilled = true
this.rejected = true
return Promise.reject(x)
})
}
then(fn) {
this[PROMISE].then(fn)
return this
}
catch(fn) {
this[PROMISE].catch(fn)
return this
}
static resolve(x) {
return new QueryablePromise((res) => res(x))
}
static reject(x) {
return new QueryablePromise((_, rej) => rej(x))
}
}
const resolvedPromise = new QueryablePromise((res) => {
setTimeout(res, 200, 'resolvedPromise')
})
const rejectedPromise = new QueryablePromise((_, rej) => {
setTimeout(rej, 200, 'rejectedPromise')
})
// ensure our promises have not been fulfilled
console.log('test 1 before: is resolved', resolvedPromise.resolved)
console.log('test 2 before: is rejected', rejectedPromise.rejected)
setTimeout(() => {
// check to see the resolved status of our promise
console.log('test 1 after: is resolved', resolvedPromise.resolved)
console.log('test 2 after: is rejected', rejectedPromise.rejected)
}, 300)
// make sure we can immediately resolve a QueryablePromise
const immediatelyResolvedPromise = QueryablePromise.resolve('immediatelyResolvedPromise')
// ensure we can chain then
.then(trace('test 3 resolved'))
.then(trace('test 3 resolved 2'))
.catch(trace('test 3 rejected'))
// make sure we can immediately reject a QueryablePromise
const immediatelyRejectedPromise = QueryablePromise.reject('immediatelyRejectedPromise')
.then(trace('test 4 resolved'))
.catch(trace('test 4 rejected'))
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js"></script>
在节点中,写入未记录的内部进程。
> process.binding('util').getPromiseDetails(Promise.resolve({data: [1,2,3]}));
[ 1, { data: [ 1, 2, 3 ] } ]
> process.binding('util').getPromiseDetails(Promise.reject(new Error('no')));
[ 2, Error: no ]
> process.binding('util').getPromiseDetails(new Promise((resolve) => {}));
[ 0, <1 empty item> ]
如果你正在使用ES7实验版,你可以使用async轻松地包装你想要收听的承诺。
async function getClient() {
let client, resolved = false;
try {
client = await new Promise((resolve, reject) => {
let client = new Client();
let timer = setTimeout(() => {
reject(new Error(`timeout`, 1000));
client.close();
});
client.on('ready', () => {
if(!resolved) {
clearTimeout(timer);
resolve(client);
}
});
client.on('error', (error) => {
if(!resolved) {
clearTimeout(timer);
reject(error);
}
});
client.on('close', (hadError) => {
if(!resolved && !hadError) {
clearTimeout(timer);
reject(new Error("close"));
}
});
});
resolved = true;
} catch(error) {
resolved = true;
throw error;
}
return client;
}
更新:2019
Bluebird.js提供了这个:http://bluebirdjs.com/docs/api/isfulfilled.html
var Promise = require("bluebird");
let p = Promise.resolve();
console.log(p.isFulfilled());
如果您更喜欢创建自己的包装器,这里有一个关于它的不错的博客。
因为JavaScript是单线程的,所以很难找到一个足够常见的用例来证明将其放在规范中是正确的。知道承诺是否被解决的最佳位置是在.then()中。测试Promise是否被履行将创建一个轮询循环,这很可能是错误的方向。
如果你想同步推理异步代码,Async /await是一个很好的结构。
await this();
await that();
return 'success!';
另一个有用的调用是Promise.all()
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
当我第一次得到这个答案时,这就是我正在寻找的用例。