如何同步确定JavaScript Promise的状态?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何同步确定JavaScript Promise的状态?相关的知识,希望对你有一定的参考价值。
我有一个纯javascript承诺(内置实现或poly-fill):
var promise = new Promise(function (resolve, reject) /* ... */ );
从specification,Promise可以是以下之一:
- '已定居'和'已解决'
- '已定居'和'被拒绝'
- “待定”
我有一个用例,我希望同步询问Promise并确定:
- 承诺落户了吗?
- 如果是这样,Promise是否已解决?
我知道我可以使用#then()
来安排在Promise更改状态后异步执行的工作。我不是问怎么做。
这个问题具体是关于Promise状态的同步审讯。我怎样才能做到这一点?
对于本机JavaScript承诺,不存在此类同步检查API。用本机承诺做这件事是不可能的。规范没有指定这样的方法。
Userland库可以做到这一点,如果您的目标是特定引擎(如v8)并且可以访问平台代码(也就是说,您可以在核心中编写代码),那么您可以使用特定工具(如私有符号)来实现此目的。这是超级特定的,而不是用户区。
在节点中,比如undocumented internal 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> ]
您可以做的是使用变量来存储状态,手动将状态设置为该变量,并检查该变量。
var state = 'pending';
new Promise(function(ff, rjc)
//do something async
if () //if success
state = 'resolved';
ff();//
else
state = 'rejected';
rjc();
);
console.log(state);//check the state somewhere else in the code
当然,这意味着您必须能够访问承诺的原始代码。如果你不这样做,那么你可以这样做:
var state = 'pending';
//you can't access somePromise's code
somePromise.then(function()
state = 'resolved';
, function()
state = 'rejected';
)
console.log(state);//check the promise's state somewhere else in the code
我的解决方案是更多编码,但我认为您可能不必为您使用的每个承诺执行此操作。
从Node.js版本8开始,您现在可以使用wise-inspection包同步检查本机承诺(没有任何危险的黑客攻击)。
您可以向Promise.prototype添加方法。它看起来像这样:
编辑:第一个解决方案无法正常工作,就像这里的大多数答案一样。它返回“pending”,直到调用异步函数“.then”,这不会立即发生。 (同样是关于使用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;
;
你可以在任何Promise上使用它。举个例子:
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
这是一个更加充实的es6版本的QueryablePromise,允许在第一次解析后链接然后捕获并立即解决或拒绝保持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>
如果你正在使用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;
我写了一个小的npm包,promise-value,它提供了一个带有resolved
标志的promise包装器:
https://www.npmjs.com/package/promise-value
它还提供对promise值(或错误)的同步访问。这不会改变Promise对象本身,而是在wrap而不是extend模式之后。
这是一个较老的问题,但我试图做类似的事情。我需要让n工人继续前进。它们的结构是承诺。我需要扫描并查看它们是否已被解决,被拒绝或仍未决定。如果已经解决,我需要该值,如果被拒绝做某事来纠正问题或待决。如果解决或拒绝,我需要开始另一项任务以保持正常。我无法想办法用Promise.all或Promise.race来做这件事,因为我继续在数组中使用promises并且找不到删除它们的方法。所以我创造了一个能够解决问题的工人
我需要一个promise生成器函数,它返回一个在必要时解析或拒绝的promise。它由一个函数调用,该函数设置框架以了解承诺正在做什么。
在下面的代码中,生成器只返回基于setTimeout的promise。
这里是
//argObj should be of form
// succeed: <true or false, nTimer: <desired time out>以上是关于如何同步确定JavaScript Promise的状态?的主要内容,如果未能解决你的问题,请参考以下文章
[万字详解]JavaScript 中的异步模式及 Promise 使用
js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)