我有一个纯JavaScript承诺(内置实现或poly-fill):
var promise = new promise(函数(解析,拒绝){/*…* /});
从规范来看,Promise可以是:
" settle "和" resolved "
“解决”和“拒绝”
“等待”
我有一个用例,我希望同步审问承诺并确定:
承诺达成了吗?
如果是,承诺解决了吗?
我知道我可以使用#then()来安排在Promise改变状态后异步执行的工作。我不是在问你该怎么做。
这个问题是关于Promise状态的同步询问。我怎样才能做到这一点呢?
似乎没有人想出一个不需要任何技巧的最简单的解决方案:
定义一个变量来指示承诺正在运行
在promise中添加.finally子句,将变量设置为false(可以在promise创建后的任何时间执行)
之后,在代码中检查上述变量是否为真或假,以查看Promise是否仍在运行。
如果你不只是想知道它是否完成了,那么除了.finally之外,还要添加.then和.catch子句,将变量设置为"resolved"或"rejected"。
唯一的缺点是,在添加子句时,状态变量不会立即(同步地)设置,以防承诺已经完成。因此,最好将其添加到创建承诺后最早的位置。
例子:
async function worker(){
// wait a very short period of time
await (new Promise(resolve => setTimeout(resolve, 100)))
//...
}
const w1=worker()
let w1_running=true
w1.finally( ()=> {w1_running=false});
//...
//Then check if it's running
(async ()=>{
while(true){
if (w1_running) {
console.log("Still Busy :(")
} else {
console.log("All done :)")
break
}
await (new Promise(resolve => setTimeout(resolve, 10)))
}
})()
// Note we need some async action started otherwise the event loop would never reach the code in the function `worker` or in the `.finally` clause
还有另一种优雅而俗气的方法来检查一个promise是否仍然挂起,只需将整个对象转换为字符串,并在inspect的帮助下检查它,就像这样:util.inspect(myPromise).includes("pending")。
在Node.js 8、9、10、11、12、13上测试
这里有一个完整的例子
const util = require("util")
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
(async ()=>{
let letmesleep = sleep(3000)
setInterval(()=>{
console.log(util.inspect(letmesleep).includes("pending"))
},1000)
})()
结果:
true
true
false
false
false
更新: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"]
当我第一次得到这个答案时,这就是我正在寻找的用例。
您可以扩展Promise类来创建一个新的可查询的Promise
类。
您可以通过继承本机可用的Promise类来创建自己的子类,比如QueryablePromise,它的实例上有一个可用的status属性,您可以使用该属性同步查询Promise对象的状态。它的实现可以在下面看到,或者参考这个来获得更好的解释。
class QueryablePromise extends Promise {
constructor (executor) {
super((resolve, reject) => executor(
data => {
resolve(data)
this._status = 'Resolved'
},
err => {
reject(err)
this._status = 'Rejected'
},
))
this._status = 'Pending'
}
get status () {
return this._status
}
}
// Create a promise that resolves after 5 sec
var myQueryablePromise = new QueryablePromise((resolve, reject) => {
setTimeout(() => resolve(), 5000)
})
// Log the status of the above promise every 500ms
setInterval(() => {
console.log(myQueryablePromise.status)
}, 500)
我发现这个解决方案很简单,并且允许我继续使用本机承诺,但添加了有用的同步检查。我也不需要动用整个承诺库。
注意:只有在当前执行线程中出现某种中断,允许promise在检查同步结构之前执行时,这才有效。这使得它比我最初想象的用处更有限——尽管对我的用例仍然有用(感谢Benjamin Gruenbaum指出这一点)。
/**
* This function allow you to modify a JS Promise by adding some status properties.
* Based on: http://stackoverflow.com/questions/21485545/is-there-a-way-to-tell-if-an-es6-promise-is-fulfilled-rejected-resolved
* But modified according to the specs of promises : https://promisesaplus.com/
*/
function MakeQuerablePromise(promise) {
// Don't modify any promise that has been already modified.
if (promise.isFulfilled) return promise;
// Set initial state
var isPending = true;
var isRejected = false;
var isFulfilled = false;
// Observe the promise, saving the fulfillment in a closure scope.
var result = promise.then(
function(v) {
isFulfilled = true;
isPending = false;
return v;
},
function(e) {
isRejected = true;
isPending = false;
throw e;
}
);
result.isFulfilled = function() { return isFulfilled; };
result.isPending = function() { return isPending; };
result.isRejected = function() { return isRejected; };
return result;
}
wrappedPromise = MakeQueryablePromise(Promise.resolve(3));
setTimeout(function() {console.log(wrappedPromise.isFulfilled())}, 1);
来自https://ourcodeworld.com/articles/read/317/how-to-check-if-a-javascript-promise-has-been-fulfilled-rejected-or-resolved,他们的答案是:是否有一种方法来判断一个ES6承诺是否被履行/拒绝/解决?