如何同步确定 JavaScript Promise 的状态?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30564053/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I synchronously determine a JavaScript Promise's state?
提问by jokeyrhyme
I have a pure JavaScript Promise (built-in implementation or poly-fill):
我有一个纯 JavaScript Promise(内置实现或 poly-fill):
var promise = new Promise(function (resolve, reject) { /* ... */ });
var promise = new Promise(function (resolve, reject) { /* ... */ });
From the specification, a Promise can be one of:
根据规范,Promise 可以是以下之一:
- 'settled' and 'resolved'
- 'settled' and 'rejected'
- 'pending'
- “已解决”和“已解决”
- “已解决”和“已拒绝”
- '待办的'
I have a use case where I wish to interrogate the Promise synchronously and determine:
我有一个用例,我希望同步询问 Promise 并确定:
is the Promise settled?
if so, is the Promise resolved?
Promise 解决了吗?
如果是这样,Promise 是否已解决?
I know that I can use #then()to schedule work to be performed asynchronously after the Promise changes state. I am NOT asking how to do this.
我知道我可以#then()用来安排在 Promise 更改状态后异步执行的工作。我不是在问如何做到这一点。
This question is specifically about synchronous interrogation of a Promise's state. How can I achieve this?
这个问题特别是关于Promise 状态的同步询问。我怎样才能做到这一点?
采纳答案by Benjamin Gruenbaum
No such synchronous inspection API exists for native JavaScript promises.It is impossible to do this with native promises. The specification does not specify such a method.
本机 JavaScript 承诺不存在此类同步检查 API。使用本机承诺是不可能做到这一点的。规范没有指定这样的方法。
Userland libraries can do this, and if you're targeting a specific engine (like v8) and have access to platform code(that is, you can write code in core) then you can use specific tools (like private symbols) to achieve this. That's super specific though and not in userland.
Userland 库可以做到这一点,如果您的目标是特定引擎(例如 v8)并且可以访问平台代码(即您可以在core 中编写代码),那么您可以使用特定工具(例如私有符号)来实现这一点. 虽然这是超级具体的,而不是在用户领域。
回答by 0xaB
promise-status-asyncdoes the trick. It is async but it does not use thento wait the promise to be resolved.
promise-status-async可以解决问题。它是异步的,但它不then用于等待承诺得到解决。
const {promiseStatus} = require('promise-status-async');
// ...
if (await promiseStatus(promise) === 'pending') {
const idle = new Promise(function(resolve) {
// can do some IDLE job meanwhile
});
return idle;
}
回答by jib
Nope, no sync API, but here's my version of the async promiseState(with help from @Matthijs):
不,没有同步 API,但这是我的异步版本promiseState(在@Matthijs 的帮助下):
function promiseState(p) {
const t = {};
return Promise.race([p, t])
.then(v => (v === t)? "pending" : "fulfilled", () => "rejected");
}
var a = Promise.resolve();
var b = Promise.reject();
var c = new Promise(() => {});
promiseState(a).then(state => console.log(state)); // fulfilled
promiseState(b).then(state => console.log(state)); // rejected
promiseState(c).then(state => console.log(state)); // pending
回答by Steween
You can make a race with Promise.resolve
It's not synchronous but happens now
你可以用 Promise.resolve 进行比赛
这不是同步的,但现在发生了
function promiseState(p, isPending, isResolved, isRejected) {
Promise.race([p, Promise.resolve('a value that p should not return')]).then(function(value) {
if (value == 'a value that p should not return') {
(typeof(isPending) === 'function') && isPending();
}else {
(typeof(isResolved) === 'function') && isResolved(value);
}
}, function(reason) {
(typeof(isRejected) === 'function') && isRejected(reason);
});
}
A little script for testing and understand their meaning of asynchronously
一个用于测试和理解异步含义的小脚本
var startTime = Date.now() - 100000;//padding trick "100001".slice(1) => 00001
function log(msg) {
console.log((""+(Date.now() - startTime)).slice(1) + ' ' + msg);
return msg;//for chaining promises
};
function prefix(pref) { return function (value) { log(pref + value); return value; };}
function delay(ms) {
return function (value) {
var startTime = Date.now();
while(Date.now() - startTime < ms) {}
return value;//for chaining promises
};
}
setTimeout(log, 0,'timeOut 0 ms');
setTimeout(log, 100,'timeOut 100 ms');
setTimeout(log, 200,'timeOut 200 ms');
var p1 = Promise.resolve('One');
var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, "Two"); });
var p3 = Promise.reject("Three");
p3.catch(delay(200)).then(delay(100)).then(prefix('delayed L3 : '));
promiseState(p1, prefix('p1 Is Pending '), prefix('p1 Is Resolved '), prefix('p1 Is Rejected '));
promiseState(p2, prefix('p2 Is Pending '), prefix('p2 Is Resolved '), prefix('p2 Is Rejected '));
promiseState(p3, prefix('p3 Is Pending '), prefix('p3 Is Resolved '), prefix('p3 Is Rejected '));
p1.then(prefix('Level 1 : ')).then(prefix('Level 2 : ')).then(prefix('Level 3 : '));
p2.then(prefix('Level 1 : ')).then(prefix('Level 2 : ')).then(prefix('Level 3 : '));
p3.catch(prefix('Level 1 : ')).then(prefix('Level 2 : ')).then(prefix('Level 3 : '));
log('end of promises');
delay(100)();
log('end of script');
results with delay(0) (comment the while in delay)
结果延迟(0)(评论延迟)
00001 end of promises
00001 end of script
00001 Level 1 : One
00001 Level 1 : Three
00001 p1 Is Resolved One
00001 p2 Is Pending undefined
00001 p3 Is Rejected Three
00001 Level 2 : One
00001 Level 2 : Three
00001 delayed L3 : Three
00002 Level 3 : One
00002 Level 3 : Three
00006 timeOut 0 ms
00100 timeOut 100 ms
00100 Level 1 : Two
00100 Level 2 : Two
00101 Level 3 : Two
00189 timeOut 200 ms
and the results of this test with firefox(chrome keep the order)
以及使用 firefox 测试的结果(chrome 保持顺序)
00000 end of promises
00100 end of script
00300 Level 1 : One
00300 Level 1 : Three
00400 p1 Is Resolved One
00400 p2 Is Pending undefined
00400 p3 Is Rejected Three
00400 Level 2 : One
00400 Level 2 : Three
00400 delayed L3 : Three
00400 Level 3 : One
00400 Level 3 : Three
00406 timeOut 0 ms
00406 timeOut 100 ms
00406 timeOut 200 ms
00406 Level 1 : Two
00407 Level 2 : Two
00407 Level 3 : Two
promiseState make .race and .then : Level 2
promiseState make .race 和 .then :级别 2
回答by rabbitco
You can use an (ugly) hack in Node.js until a native method is offered:
在提供本机方法之前,您可以在 Node.js 中使用(丑陋的)hack:
util = require('util');
var promise1 = new Promise (function (resolve) {
}
var promise2 = new Promise (function (resolve) {
resolve ('foo');
}
state1 = util.inspect (promise1);
state2 = util.inspect (promise2);
if (state1 === 'Promise { <pending> }') {
console.log('pending'); // pending
}
if (state2 === "Promise { 'foo' }") {
console.log ('foo') // foo
}
回答by amara
in node, say undocumented internalprocess.binding('util').getPromiseDetails(promise)
在节点中,说无证内部process.binding('util').getPromiseDetails(promise)
> 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> ]
回答by SpiderPig
You can wrap your promises in this way
你可以用这种方式包装你的承诺
function wrapPromise(promise) {
var value, error,
settled = false,
resolved = false,
rejected = false,
p = promise.then(function(v) {
value = v;
settled = true;
resolved = true;
return v;
}, function(err) {
error = err;
settled = true;
rejected = true;
throw err;
});
p.isSettled = function() {
return settled;
};
p.isResolved = function() {
return resolved;
};
p.isRejected = function() {
return rejected;
};
p.value = function() {
return value;
};
p.error = function() {
return error;
};
var pThen = p.then, pCatch = p.catch;
p.then = function(res, rej) {
return wrapPromise(pThen(res, rej));
};
p.catch = function(rej) {
return wrapPromise(pCatch(rej));
};
return p;
}
回答by Michael Cole
Updated: 2019
更新时间:2019
Bluebird.js offers this: http://bluebirdjs.com/docs/api/isfulfilled.html
Bluebird.js 提供:http: //bluebirdjs.com/docs/api/isfulfilled.html
var Promise = require("bluebird");
let p = Promise.resolve();
console.log(p.isFulfilled());
If you'd prefer to create your own wrapper, here is a nice blogabout it.
如果您更喜欢创建自己的包装器,这里有一个关于它的不错的博客。
Because JavaScript is single-threaded, it's hard to find a common enough use case to justify putting this in the spec. The best place to know if a promise is resolved is in .then(). Testing if a Promise is fullfilled would create a polling loop which is most likely the wrong direction.
因为 JavaScript 是单线程的,所以很难找到一个足够常见的用例来证明将其放入规范中。了解 Promise 是否已解决的最佳位置是在 .then() 中。测试 Promise 是否已满会创建一个轮询循环,这很可能是错误的方向。
async/awaitis a nice construct if you'd like to reason async code synchronously.
如果您想同步推理异步代码,async/await是一个不错的构造。
await this();
await that();
return 'success!';
Another useful call is Promise.all()
另一个有用的调用是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"]
When I first reached for this answer, that is the use case I was looking for.
当我第一次找到这个答案时,这就是我正在寻找的用例。
回答by Matthijs
It's indeed quite annoying that this basic functionality is missing. If you're using node.js then I know of two workarounds, neither of 'em very pretty. Both snippets below implement the same API:
缺少这个基本功能确实很烦人。如果您使用的是 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' }
There doesn't seem to be any way to distinguish the last two promise states using either trick.
似乎没有任何方法可以使用任何一种技巧来区分最后两个承诺状态。
1. Use the V8 debug API
1.使用V8调试API
This is the same trick that util.inspectuses.
这与util.inspect使用的技巧相同。
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 fwor-up
status = 'fulfilled';
let value = mirror.promiseValue().value();
return { status, value };
};
2. Synchronously run microtasks
2. 同步运行微任务
This avoids the debug API, but has some frightening semantics by causing all pending microtasks and process.nextTickcallbacks to be run synchronously. It also has the side-effect of preventing the "unhandled promise rejection" error from ever being triggered for the inspected promise.
这避免了调试 API,但通过使所有挂起的微任务和process.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 };
};
回答by Scott Rudiger
Caveat: This method uses undocumented Node.js internals and could be changed without warning.
警告:此方法使用未记录的 Node.js 内部结构,可以在没有警告的情况下进行更改。
In Node you can synchronously determine a promise's state using process.binding('util').getPromiseDetails(/* promise */);.
在 Node 中,您可以使用process.binding('util').getPromiseDetails(/* promise */);.
This will return:
这将返回:
[0, ]for pending,
[0, ]待定,
[1, /* value */]for fulfilled, or
[1, /* value */]为完成,或
[2, /* value */]for rejected.
[2, /* value */]对于被拒绝。
const pending = new Promise(resolve => setTimeout(() => resolve('yakko')));;
const fulfilled = Promise.resolve('wakko');
const rejected = Promise.reject('dot');
[pending, fulfilled, rejected].forEach(promise => {
console.log(process.binding('util').getPromiseDetails(promise));
});
// pending: [0, ]
// fulfilled: [1, 'wakko']
// rejected: [2, 'dot']
Wrapping this into a helper function:
将其包装成一个辅助函数:
const getStatus = promise => ['pending', 'fulfilled', 'rejected'][
process.binding('util').getPromiseDetails(promise)[0]
];
getStatus(pending); // pending
getStatus(fulfilled); // fulfilled
getStatus(rejected); // rejected


