如何同步确定JavaScript Promise的状态?

时间:2015-06-01 00:16:24

标签: javascript promise es6-promise

我有一个纯粹的JavaScript Promise(内置实现或poly-fill):

var promise = new Promise(function (resolve, reject) { /* ... */ });

来自specification,承诺可以是以下之一:

  • '结算'和'已解决'
  • '结算'并且'拒绝'
  • '未决'

我有一个用例,我希望同步询问Promise并确定:

  • 是承诺落户吗?

  • 如果是,Promise是否已解决?

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

这个问题具体是关于对Promise州的同步审讯。我怎样才能做到这一点?

26 个答案:

答案 0 :(得分:58)

本机JavaScript承诺不存在此类同步检查API。使用本机承诺无法执行此操作。规范没有指定这样的方法。

Userland库可以执行此操作,如果您针对特定引擎(如v8)并且可以访问平台代码(也就是说,您可以在核心中编写代码)然后您可以使用特定工具(如私有符号)来实现此目的。这虽然超级具体但不在用户区。

答案 1 :(得分:29)

enter image description here

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

答案 2 :(得分:16)

不,没有同步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




答案 3 :(得分:15)

你可以和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);
  });
}

用于测试和理解其异步含义的小脚本

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');

结果有延迟(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

并使用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和.then:Level 2

答案 4 :(得分:8)

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

答案 5 :(得分:4)

这个基本功能缺失确实令人讨厌。如果您正在使用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.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 fuck-up
        status = 'fulfilled';
    let value = mirror.promiseValue().value();
    return { status, value };
};

2。同步运行微任务

这避免了调试API,但是通过使所有挂起的微任务和process.nextTick回调同步运行,有一些可怕的语义。它还具有防止&#34;未处理的承诺拒绝的副作用。因被检查的承诺而被触发的错误。

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

答案 6 :(得分:4)

注意:此方法使用未记录的Node.js内部结构,可以在不发出警告的情况下进行更改。

在Node中,您可以使用process.binding('util').getPromiseDetails(/* promise */);同步确定承诺状态。

这将返回:

[0, ](待定)

[1, /* value */]为完成,或

[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']

将其包装到一个辅助函数中:

const getStatus = promise => ['pending', 'fulfilled', 'rejected'][
  process.binding('util').getPromiseDetails(promise)[0]
];

getStatus(pending); // pending
getStatus(fulfilled); // fulfilled
getStatus(rejected); // rejected

答案 7 :(得分:4)

更新:2019年

Bluebird.js提供:http://bluebirdjs.com/docs/api/isfulfilled.html

var Promise = require("bluebird");
let p = Promise.resolve();
console.log(p.isFulfilled());

如果您更喜欢创建自己的包装器,请参阅nice blog

因为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"]

当我第一次找到这个答案时,那就是我正在寻找的用例。

答案 8 :(得分:4)

你可以用这种方式包装你的承诺

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

答案 9 :(得分:3)

节点中的

,请说undocumented internal Private Sub CommandButton1_Click() Dim OrderDate As String, Job As String, AccountManager As String Dim Site As String, DueDate As String, BudgetedHours As String `enter code here`Supervisor As String Dim TotalPieces As String, Billedhours As String, UnitsCompleted As String Dim EmployeeName As String, Task As String Dim StartTime As String, FinishTime As String, TotalTime As String Dim Notes As String Worksheets("Assembly Work Form").Select Date = Range("B3") Job = Range("B4") CustomerName = Range("B5") AccountManager = Range("B7") Supervisor = Range("B8") Site = Range("B9") DueDate = Range("B10") BudgetedHours = Range("B11") TotalPieces = Range("F5") Billedhours = Range("F3") UnitsCompleted = Range("F6") EmployeeName = Range("B15") Task = Range("B15") StartTime = ("E17") FinishTime = ("G17") TotalTime = ("I17") Notes = Range("K17") Worksheets("AssemblyTotals").Select Worksheets("AssemblyTotals").Range("A2").Select If Worksheets("AssemblyTotals").Range("A3").Offset("1,0") <> "" Then Worksheets("AssemblyTotals").Range("A2").End(xlDown).Select End If ActiveCell.Offset(1, 0).Select ActiveCell.Value = Date ActiveCell.Offset(0, 1).Select ActiveCell.Value = Job ActiveCell.Offset(-1, 0).Select`enter code here` ActiveCell.Value = CustomerName Worksheets("Assembly Work Form").Select Worksheets("Assembly Work Form").Range("DataFields").ClearContents End Sub

process.binding('util').getPromiseDetails(promise)

答案 10 :(得分:2)

你可以做的是使用变量来存储状态,手动将状态设置为该变量,并检查该变量。

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

我的解决方案是更多编码,但我认为您可能不必为您使用的每个承诺执行此操作。

答案 11 :(得分:2)

从Node.js版本8开始,您现在可以使用wise-inspection包来同步检查本机承诺(没有任何危险的黑客攻击)。

答案 12 :(得分:2)

您可以向Promise.prototype添加方法。它看起来像这样:

编辑:第一个解决方案无法正常工作,就像这里的大部分答案一样。它返回&#34;待定&#34;直到异步功能&#34; .then&#34;被调用,这不会立即发生。 (同样是关于使用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;
                }
            }
        }
    };
}

并使用它:

注意:在此解决方案中,您不必使用&#34; new&#34;运营商。

myPromise = Promise.stateable(myFunction);
console.log(myPromise.state); // pending|resolved|rejected

答案 13 :(得分:2)

还有另一种优雅的方法,可以通过仅将整个对象转换为字符串并借助诸如util.inspect(myPromise).includes("pending")的检查来检查诺言是否仍然未完成。 / p>

在Node.js 8,9,10,11,12,13上测试

这是一个完整的例子

const util = require("util")

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

(async ()=>{
  let letmesleep = sleep(3000)
  setInterval(()=>{
    console.log(util.inspect(letmesleep).includes("pending"))
  },1000)
})()

结果:

true
true
false
false
false

答案 14 :(得分:1)

注意:process.binding('util').getPromiseDetails 在节点 16 上为 undefined

基准:

候选人:

/**
 * https://stackoverflow.com/a/47009572/5318303
 */
const isPromisePending1 = (() => { // noinspection JSUnresolvedFunction
    const util = process.binding('util')  // noinspection JSUnresolvedFunction
    return promise => !util.getPromiseDetails(promise)[0]
})()

/**
 * https://stackoverflow.com/a/35852666/5318303
 */
const isPromisePending2 = (promise) => util.inspect(promise) === 'Promise { <pending> }'

/**
 * https://stackoverflow.com/a/35820220/5318303
 */
const isPromisePending3 = (promise) => {
    const t = {}
    return Promise.race([promise, t])
            .then(v => v === t, () => false)
}

测试承诺:

const a = Promise.resolve()
const b = Promise.reject()
const c = new Promise(() => {})
const x = (async () => 1)()

运行基准测试:

const n = 1000000

console.time('isPromisePending1')
for (let i = 0; i < n; i++) {
    isPromisePending1(a)
    isPromisePending1(b)
    isPromisePending1(c)
    isPromisePending1(x)
}
console.timeEnd('isPromisePending1')

console.time('isPromisePending2')
for (let i = 0; i < n; i++) {
    isPromisePending2(a)
    isPromisePending2(b)
    isPromisePending2(c)
    isPromisePending2(x)
}
console.timeEnd('isPromisePending2')

console.time('isPromisePending3')
for (let i = 0; i < n; i++) {
    await isPromisePending3(a)
    await isPromisePending3(b)
    await isPromisePending3(c)
    await isPromisePending3(x)
}
console.timeEnd('isPromisePending3')

结果:

isPromisePending1: 440.694ms
isPromisePending2: 3.354s
isPromisePending3: 4.761s

显然 isPromisePending1() 太快了(8~10 倍)!但它在节点 16 上不可用! (见上面的警告)。

答案 15 :(得分:1)

我查看了针对此问题提出的解决方案,但没有找到与我在 Node.js 中使用的简单方法相对应的解决方案。

我定义了一个简单的类 PromiseMonitor,它接受一个 promise 作为其构造函数的单个参数,并且有一个字符串属性 .status,它返回对应于 promise 状态的标准字符串值,“pending”,“已解决”或“已拒绝”,以及四个布尔属性 .pending.resolved.rejected.error。仅当 .error 为 true 并且拒绝回调被传递了一个 Error 对象时,属性 .rejected 才设置为 true。

该类只是在承诺上使用 .then() 来在承诺被解决或拒绝时更改 PromiseMonitor 的状态。它不会干扰原始承诺的任何其他用途。代码如下:

class PromiseMonitor {
    constructor(prm){
        this._status = "pending";
        this._pending = true;
        this._resolved = false;
        this._rejected = false;
        this._error = false;
        prm
            .then( ()=>{  
                        this._status = "resolved"; 
                        this._resolved = true; 
                        this._pending = false; 
                    } 
                , (err)=>{ 
                        this._status = "rejected";
                        this._pending = false;
                        this._rejected = true;
                        this._error = err instanceof Error ? true: false ; 
                    } 
                );
    }

    get status(){ return this._status; };
    get pending(){ return this._pending; };
    get resolved(){ return this._resolved; };
    get rejected(){ return this._rejected; };
    get error(){ return this._error };
};

要监控 Promise 的状态,只需创建一个 PromiseMonitor 实例,将 Promise 作为参数传入,例如:

let promiseObject = functionThatReturnsAPromise();
let promiseMonitor = new PromiseMonitor( promiseObject );

现在你可以同步检查promiseMonitor的所有属性,它会跟踪原始promise的状态。这是一个测试脚本,演示了被监控的承诺的三种可能的解决方案。

let ticks = 0;
let tickerID = setInterval( ()=>{++ticks; console.log(`..tick ${ticks}`)}, 1000);

async function run(){
    console.log("Start");

    let delay = prmDelay(2000);
    let delayMonitor = new PromiseMonitor(delay);

    // normal handling of delay promise
    delay.then((result)=>( console.log("Normal resolution of delay using .then()") ) );

    console.log("delay at start:\n", delay);
    console.log("delayMonitor at start:\n", delayMonitor);
    await delay;
    console.log("delay finished:\n", delay);
    console.log("delayMonitor finished:\n", delayMonitor);


    console.log("\n\n TEST2: Rejection without an Error test ================================")
    let rejDelay = prmDelay(3000, "reject");
    let rejMonitor = new PromiseMonitor(rejDelay);

    // normal handling of reject result on promise
    rejDelay.then((result)=>( console.log("Normal resolution of rejDelay using .then will not happen") ) 
                    , (err)=>( console.log("Rejection of rejDelay handled using .then")));

    console.log("rejDelay at start:\n", rejDelay);
    console.log("rejMonitor at start:\n", rejMonitor);

    await rejDelay.catch( (err)=>{ console.log( "Caught error using .catch on rejDelay" ); });

    console.log("rejDelay finished:\n", rejDelay);
    console.log("rejMonitor finished:\n", rejMonitor);


    console.log("\n\n TEST3: Rejection with an Error test ================================")
    let errMonitor ;
    let errDelay;
    try{

        errDelay = prmDelay(1000, "error");
        errMonitor = new PromiseMonitor(errDelay);
        
        // normal handling of results of the original promise
        errDelay.then(
            (result)=>{ 
                console.log("Normal expiry of errDelay");
                console.log("Monitor Status is " + errMonitor.status )
            } 
            , (err)=>{
                console.log("** Rejection of errDelay handled using .then()");
                console.log("   Monitor Status is " + errMonitor.status )
            }
        );

        console.log("errDelay at start:\n", errDelay);
        console.log("errMonitor at start:\n", errMonitor);

        await errDelay;

        console.log("**** This should never be run");

    } catch(err) { 

        console.log( "** Caught error on errDelay using try{}catch{}:" ); 
        console.log( "   Monitor Status is " + errMonitor.status )

    };

    console.log("errDelay finished:\n", errDelay);
    console.log("errMonitor finished:\n", errMonitor);
    

    clearInterval(tickerID);


}

/**
 * Creates a new promise with a specific result
 * @param {*} tt 
 * @param {*} exitType ("resolve", "reject" or "error")
 */
function prmDelay (tt, exitType) {
    
    return new Promise(function(resolve, reject) {
        if( exitType == 'reject' ){
            setTimeout(()=>{ reject("REJECTED")}, tt);
        } else if( exitType== 'error'){
            setTimeout(()=>{ reject(new Error( "ERROR Rejection") ); }, tt);
        } else {
            setTimeout(()=>{ resolve("RESOLVED") }, tt);
        } ;
    });
};


run();

答案 16 :(得分:1)

这是QueryablePromise的一个更加充实的es6版本,可以链接然后在第一个解析后捕获并立即解析或拒绝以使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>

答案 17 :(得分:0)

scrollView.mask = UIView(frame: scrollView.frame) scrollView.mask?.backgroundColor = UIColor.black.withAlphaComponent(0.25) scrollView.isUserInteractionEnabled = false @jib's answer的用法,具有惯用的原型制作。

await

请注意,此异步功能像同步功能一样(几乎实际上是立即执行)立即“几乎”执行。

答案 18 :(得分:0)

2019:

据我所知,最简单的方法是extension UnsafeMutableRawPointer { func toArray<T>(to type: T.Type, capacity count: Int) -> [T]{ let pointer = bindMemory(to: type, capacity: count) return Array(UnsafeBufferPointer(start: pointer, count: count)) } } ,它是对promise或任何异步工作的超薄包装。

var array = [1,2,3,4,5]
let ponter = UnsafeMutableRawPointer(mutating: array)
print(ponter.toArray(to: Int.self, capacity: array.count))

答案 19 :(得分:0)

  

您可以extend Promise类来创建新的可查询 Promise   课。

您可以通过继承本地可用的QueryablePromise类来创建自己的子类,例如Promise,该类的实例将具有一个status属性,您可以使用该属性同步查询承诺对象的状态。可以在下面看到它的实现,也可以参考this以获得更好的解释。

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)

答案 20 :(得分:0)

这是一个较老的问题,但我试图做类似的事情。我需要让n工人继续前进。它们的结构是承诺。我需要扫描并查看它们是否已被解决,被拒绝或仍未决定。如果已经解决,我需要该值,如果被拒绝做某事来纠正问题或待决。如果解决或拒绝,我需要开始另一项任务以保持正常。我无法想办法用Promise.all或Promise.race来做这件事,因为我继续在数组中使用promises并且找不到删除它们的方法。所以我创建了一个可以解决问题的工作者

我需要一个promise生成器函数,它返回一个在必要时解析或拒绝的promise。它由一个函数调用,该函数设置框架以了解承诺正在做什么。

在下面的代码中,生成器只返回基于setTimeout的promise。

这是

//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中测试

BTW不是在这个答案中,但在其他类似主题的答案中,我讨厌当有人说“你不理解”或“那不是它的工作方式”时我通常认为提问者知道他们想要什么。建议一个更好的方法是伟大的。关于承诺如何运作的患者解释也将是好的。

答案 21 :(得分:0)

有很多答案的老问题,但似乎没有一个问题表明我认为最简单的解决方案:在承诺解决/拒绝上设置一个布尔指标。

class Promise2 {
  constructor(...args) {
    let promise = new Promise(...args);
    promise.then(() => promise._resolved_ = true);
    promise.catch(() => promise._rejected_ = true);
    return promise;
  }
}

let p = new Promise2(r => setTimeout(r, 3000));

setInterval(() => {
  console.log('checking synchronously if p is resolved yet?', p._resolved_);
}, 1000);

答案 22 :(得分:0)

我写了一个小的npm包,promise-value,它提供了一个带有resolved标志的promise包装器:

https://www.npmjs.com/package/promise-value

它还提供对promise值(或错误)的同步访问。这不会改变Promise对象本身,而是在换行而不是扩展模式之后。

答案 23 :(得分:0)

这是我使用的 Future 模式:(https://github.com/Smallscript-Corp)

  • 启用 syncasync fn 使用
  • 使事件模式与async行为统一
class XPromise extends Promise {
  state = 'pending'
  get settled() {return(this.state !== 'pending')}
  resolve(v,...a) {
    this.state = 'resolved'
    return(this.resolve_(this.value = v,...a))
  }
  reject(e,...a) {
    this.state = 'rejected'
    return(this.reject_(this.value = (e instanceof Error) ? e : XPromise.Error(e),...a))
  }
  static Error(e) {const v = Error('value-rejected'); v.value = e; return(v)}
  static Future(fn,...args) { // FactoryFn
    let r,t,fv = new XPromise((r_,t_) => {r=r_;t=t_})
    fv.resolve_ = r; fv.reject_  = t;
    switch(typeof fn) {
      case 'undefined': break; case 'function': fn(fv,...args); break;
      default: fv.resolve(fn)
    }
    return(fv)
  }
}
global.Future = XPromise.Future

然后您可以创建future-value 实例,这些实例可以使用同步和异步函数解析;能够统一处理事件。

您可以使用它来编写如下模式:

async doSomething() {
  // Start both - logically async-parallel
  const fvIsNetworkOnLine = this.fvIsNetworkOnline
  const fvAuthToken = this.fvAuthToken
  // await both (order not critical since both started/queued above)
  await fvAuthToken
  await fvIsNetworkOnLine
  // ... we can check the future values here if needed `fv.resolved`, `fv.state` etc
  // ... do dependent workflow here ...
}
onNetworkOnLine(fIsOnline) {
  // We utilize the `fv.settled` below, and use the event to `settle` it etc
  if(fIsOnline) {
    if(this.fvNetworkAvailable_)
      this.fvNetworkAvailable_.resolve(true)
    this.fvNetworkAvailable_ = undefined
  }
  else if(this.fvNetworkAvailable_.settled) {
    this.fvNetworkAvailable_ = undefined
  }
}
get fvNetworkAvailable() {
  if(navigator.onLine)
    return true
  else if(this.fvNetworkAvailable_)
    return this.fvNetworkAvailable_
  return (this.fvNetworkAvailable_ = Future())
}
get fvAuthToken() {
  if(this.fvAuthToken_)
    return this.fvAuthToken_
  const authTokenFv = async fv => {
    // ... handle retry logic etc here ...
  }
  return(this.fvAuthToken_ = Future(authTokenFv))
}

答案 24 :(得分:0)

如果您正在使用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;
}

答案 25 :(得分:-1)

我发现此解决方案很简单,可以继续使用本机Promise,但可以添加有用的同步检查。我也不必引入整个诺言库。

CAVEAT:仅当当前执行线程中存在某种中断以允许诺言在检查同步结构之前执行时,此选项才起作用。这使它的实用性比我最初想象的要有限-尽管对我的用例仍然有用(感谢Benjamin Gruenbaum指出这一点)

/**
 * This function allow you to modify a JS Promise by adding some status properties.
 * Based on: http://stackoverflow.com/questions/21485545/is-there-a-way-to-tell-if-an-es6-promise-is-fulfilled-rejected-resolved
 * But modified according to the specs of promises : https://promisesaplus.com/
 */
function MakeQuerablePromise(promise) {
    // Don't modify any promise that has been already modified.
    if (promise.isFulfilled) return promise;

    // Set initial state
    var isPending = true;
    var isRejected = false;
    var isFulfilled = false;

    // Observe the promise, saving the fulfillment in a closure scope.
    var result = promise.then(
        function(v) {
            isFulfilled = true;
            isPending = false;
            return v; 
        }, 
        function(e) {
            isRejected = true;
            isPending = false;
            throw e; 
        }
    );

    result.isFulfilled = function() { return isFulfilled; };
    result.isPending = function() { return isPending; };
    result.isRejected = function() { return isRejected; };
    return result;
}

wrappedPromise = MakeQueryablePromise(Promise.resolve(3)); 
setTimeout(function() {console.log(wrappedPromise.isFulfilled())}, 1);

来自https://ourcodeworld.com/articles/read/317/how-to-check-if-a-javascript-promise-has-been-fulfilled-rejected-or-resolved的人,他们的答案基于Is there a way to tell if an ES6 promise is fulfilled/rejected/resolved?