我有一个纯JavaScript承诺(内置实现或poly-fill):

var promise = new promise(函数(解析,拒绝){/*…* /});

从规范来看,Promise可以是:

" settle "和" resolved " “解决”和“拒绝” “等待”

我有一个用例,我希望同步审问承诺并确定:

承诺达成了吗? 如果是,承诺解决了吗?

我知道我可以使用#then()来安排在Promise改变状态后异步执行的工作。我不是在问你该怎么做。

这个问题是关于Promise状态的同步询问。我怎样才能做到这一点呢?


当前回答

您可以扩展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类来创建一个新的可查询的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)

This is older question but I was trying to do something similar. I need to keep n workers going. They are structured in a promise. I need to scan and see if they are resolved, rejected or still pending. If resolved, I need the value, if rejected do something to correct the issue or pending. If resolved or rejected I need to start another task to keep n going. I can't figure a way to do it with Promise.all or Promise.race as I keep working promises in an array and can find no way to delete them. So I create a worker that does the trick

我需要一个承诺生成器函数,返回一个承诺,根据需要解决或拒绝。它由一个函数调用,该函数设置框架以了解承诺在做什么。

在下面的代码中,生成器只是返回一个基于setTimeout的承诺。

在这里

//argObj should be of form
// {succeed: <true or false, nTimer: <desired time out>}
function promiseGenerator(argsObj) {
  let succeed = argsObj.succeed;          
  let nTimer = argsObj.nTimer;
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (succeed) {
        resolve('ok');
      }
      else {
        reject(`fail`);
      }
    }, nTimer);
  })

}

function doWork(generatorargs) {
  let sp = { state: `pending`, value: ``, promise: "" };
  let p1 = promiseGenerator(generatorargs)
    .then((value) => {
      sp.state = "resolved";
      sp.value = value;
    })
    .catch((err) => {
      sp.state = "rejected";
      sp.value = err;
    })
  sp.promise = p1;
  return sp;
}

doWork返回一个包含promise及其状态和返回值的对象。

下面的代码运行一个循环,测试状态并创建新的工作线程以保持在3个正在运行的工作线程。

let promiseArray = [];

promiseArray.push(doWork({ succeed: true, nTimer: 1000 }));
promiseArray.push(doWork({ succeed: true, nTimer: 500 }));
promiseArray.push(doWork({ succeed: false, nTimer: 3000 }));

function loopTimerPromise(delay) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('ok');
    }, delay)
  })
}

async function looper() {
  let nPromises = 3;      //just for breaking loop
  let nloop = 0;          //just for breaking loop
  let i;
  //let continueLoop = true;
  while (true) {
    await loopTimerPromise(900);  //execute loop every 900ms
    nloop++;
    //console.log(`promiseArray.length = ${promiseArray.length}`);
    for (i = promiseArray.length; i--; i > -1) {
      console.log(`index ${i} state: ${promiseArray[i].state}`);
      switch (promiseArray[i].state) {
        case "pending":
          break;
        case "resolved":
          nPromises++;
          promiseArray.splice(i, 1);
          promiseArray.push(doWork({ succeed: true, nTimer: 1000 }));
          break;
        case "rejected":
          //take recovery action
          nPromises++;
          promiseArray.splice(i, 1);
          promiseArray.push(doWork({ succeed: false, nTimer: 500 }));
          break;
        default:
          console.log(`error bad state in i=${i} state:${promiseArray[i].state} `)
          break;
      }
    }
    console.log(``);
    if (nloop > 10 || nPromises > 10) {
      //should do a Promise.all on remaining promises to clean them up but not for test
      break;
    }
  }
}

looper();

在node.js中测试

顺便说一句,不是在这个问题上,而是在其他类似的问题上,我讨厌有人说“你不明白”或“事情不是这样的”,我通常认为提问者知道他们想要什么。建议一个更好的方法是很好的。耐心地解释承诺如何起作用也会很好。

老问题有很多答案,但似乎没有一个建议我认为是最简单的解决方案:在承诺解决/拒绝上设置bool指示器。

类Promise2 { 构造函数(args) { let promise = new promise(…args); promise.then(() => promise。_resolved_ = true); promise.catch(() => promise。_rejected_ = true); 返回的诺言; } } let p = new promise (r => setTimeout(r, 3000)); setInterval(() => { Console.log('正在同步检查p是否已解析?”,p._resolved_); }, 1000);

你可以在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

Promise-status-async可以做到。它是异步的,但它不使用然后等待承诺被解决。

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;
}