如何同步确定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 对象

[万字详解]JavaScript 中的异步模式及 Promise 使用

Promise对象

js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)

Twisted的延迟是否与JavaScript中的Promise相同?

JavaScript Promise理解