我有一个纯JavaScript承诺(内置实现或poly-fill):
var promise = new promise(函数(解析,拒绝){/*…* /});
从规范来看,Promise可以是:
" settle "和" resolved "
“解决”和“拒绝”
“等待”
我有一个用例,我希望同步审问承诺并确定:
承诺达成了吗?
如果是,承诺解决了吗?
我知道我可以使用#then()来安排在Promise改变状态后异步执行的工作。我不是在问你该怎么做。
这个问题是关于Promise状态的同步询问。我怎样才能做到这一点呢?
更新: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中添加.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.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
这一基本功能的缺失确实令人恼火。如果你正在使用node.js,那么我知道有两种变通方法,它们都不太漂亮。下面的两个代码段实现了相同的API:
> Promise.getInfo( 42 ) // not a promise
{ status: 'fulfilled', value: 42 }
> Promise.getInfo( Promise.resolve(42) ) // fulfilled
{ status: 'fulfilled', value: 42 }
> Promise.getInfo( Promise.reject(42) ) // rejected
{ status: 'rejected', value: 42 }
> Promise.getInfo( p = new Promise(() => {}) ) // unresolved
{ status: 'pending' }
> Promise.getInfo( Promise.resolve(p) ) // resolved but pending
{ status: 'pending' }
用这两种方法似乎都无法区分最后两种承诺状态。
1. 使用V8调试API
这和util是一样的。检查使用。
const Debug = require('vm').runInDebugContext('Debug');
Promise.getInfo = function( arg ) {
let mirror = Debug.MakeMirror( arg, true );
if( ! mirror.isPromise() )
return { status: 'fulfilled', value: arg };
let status = mirror.status();
if( status === 'pending' )
return { status };
if( status === 'resolved' ) // fix terminology fuck-up
status = 'fulfilled';
let value = mirror.promiseValue().value();
return { status, value };
};
2. 同步运行微任务
这避免了调试API,但是会导致所有挂起的微任务和进程,从而产生一些可怕的语义。nextTick回调将同步运行。它还有一个副作用,就是防止被检查的承诺触发“未处理的承诺拒绝”错误。
Promise.getInfo = function( arg ) {
const pending = {};
let status, value;
Promise.race([ arg, pending ]).then(
x => { status = 'fulfilled'; value = x; },
x => { status = 'rejected'; value = x; }
);
process._tickCallback(); // run microtasks right now
if( value === pending )
return { status: 'pending' };
return { status, value };
};