JavaScript Promise 상태를 동기적으로 판별하려면 어떻게 해야 합니까?
순수 JavaScript Promise(내장 구현 또는 폴리필):
var promise = new Promise(function (resolve, reject) { /* ... */ });
Promise는 사양에 따라 다음 중 하나가 될 수 있습니다.
- ' ' ' ' ''
- ' ' ' ' ''
- '실패'
Promise에 대해 동기적으로 질문하고 다음 사항을 결정하는 사용 사례가 있습니다.
약속은 확정되었습니까?
그렇다면 약속은 해결되었습니까?
Promise 상태가 변경된 후 를 사용하여 비동기적으로 수행할 작업을 예약할 수 있습니다.나는 이것을 어떻게 하는지 묻는 것이 아니다.
이 질문은 특히 Promise 상태에 대한 동기식 심문에 관한 것입니다.어떻게 하면 좋을까요?
네이티브 JavaScript 약속에는 이러한 동기 검사 API가 없습니다.원어민의 약속으로는 이것을 할 수 없다.사양에는 이러한 방법이 지정되어 있지 않습니다.
유저랜드 라이브러리는, 이것을 실행할 수 있습니다.특정 엔진(v8 등)을 대상으로 하고 있어 플랫폼 코드에 액세스 할 수 있는 경우(즉, 코어로 코드를 쓸 수 있는 경우), 특정 툴(프라이빗 심볼 등)을 사용하여 실행할 수 있습니다.사용자 영역에서는 그렇지 않지만 매우 구체적입니다.
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
promise-status-http c가 효과가 있습니다.비동기이지만 사용하지 않습니다.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;
}
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');
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
firefox를 사용한 이 테스트 결과(주문 유지)
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
make . and : 2promiseState make .race 및 .then : 벨벨 22
노드에서는 문서화되어 있지 않은 내부라고 합니다. 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> ]
네이티브 메서드가 제공될 때까지 Node.js에서 (추한) 해킹을 사용할 수 있습니다.
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
}
갱신일 : 2019
Bluebird.js는 다음을 제공합니다.http://bluebirdjs.com/docs/api/isfulfilled.html
var Promise = require("bluebird");
let p = Promise.resolve();
console.log(p.isFulfilled());
만약 당신이 자신만의 래퍼를 만들고 싶다면, 여기 그것에 대한 멋진 블로그가 있습니다.
JavaScript는 싱글 스레드이기 때문에 이를 스펙에 포함시킬 만한 일반적인 사용 사례를 찾기가 어렵습니다.약속이 해결되었는지 여부를 알 수 있는 가장 좋은 장소는 .then().Promise가 가득 차 있는지 테스트하면 폴링 루프가 생성되며, 폴링 루프는 잘못된 방향일 가능성이 높습니다.
비동기 코드를 동기화하고 싶다면 async/module을 사용하는 것이 좋습니다.
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"]
처음 이 답변을 얻었을 때, 그것이 바로 제가 찾고 있던 사용 사례입니다.
이 기본적인 기능이 없어 매우 짜증납니다.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
이치노검증한 약속에 대해 처리되지 않은 약속거부 오류가 발생하지 않도록 하는 부작용도 있다.
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 };
};
await
사용법을 @jib의 답변에 맞추어, 관용적인 프로토타이핑을 사용합니다.
Object.defineProperty(Promise.prototype, "state", {
get: function(){
const o = {};
return Promise.race([this, o]).then(
v => v === o ? "pending" : "resolved",
() => "rejected");
}
});
// usage: console.log(await <Your Promise>.state);
(async () => {
console.log(await Promise.resolve(2).state); // "resolved"
console.log(await Promise.reject(0).state); // "rejected"
console.log(await new Promise(()=>{}).state); // "pending"
})();
이 비동기 함수는 동기 함수와 같이 "거의" 즉시 실행됩니다(또는 실제로 즉시 실행될 수도 있습니다.
이렇게 약속을 포장할 수 있습니다.
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;
}
Promise.protype에 메서드를 추가할 수 있습니다.다음과 같습니다.
편집: 첫 번째 솔루션은 대부분의 답변과 마찬가지로 제대로 작동하지 않습니다.비동기 함수 ".then"이 호출될 때까지 "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;
};
}
모든 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;
}
}
}
};
}
사용방법:
주의: 이 솔루션에서는 "새로운" 연산자를 사용할 필요가 없습니다.
myPromise = Promise.stateable(myFunction);
console.log(myPromise.state); // pending|resolved|rejected
경고: 이 메서드는 문서화되어 있지 않은 Node.js internal을 사용하며 경고 없이 변경될 수 있습니다.
할 수 .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
오브젝트 전체를 문자열로 변환하는 것만으로 약속이 아직 보류 중인지 여부를 확인하고 다음과 같은 검사를 통해 확인할 수 있는 우아하고 진부한 방법이 있습니다.util.inspect(myPromise).includes("pending")
.
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
이 질문에 대해 제안된 솔루션을 살펴보았지만 Node.js에서 사용한 간단한 접근법에 해당하는 솔루션을 찾을 수 없었습니다.
한 클래스 PromiseMonitor를이로서 PromiseMonitor의 입니다..status
값, "commit" 또는 "commit" 및 "commit"의 4개의 속성을 합니다..pending
,.resolved
,.rejected
★★★★★★★★★★★★★★★★★」.error
... ★★★★★★★★★★★ ★.error
..rejected
는 true이며 거부 콜백은 Error 객체가 전달되었습니다.
클래스는 '우리'를 사용합니다..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 인스턴스를 만들고 약속을 매개 변수로 전달합니다.다음은 예를 제시하겠습니다.
let promiseObject = functionThatReturnsAPromise();
let promiseMonitor = new PromiseMonitor( promiseObject );
이제 promiseMonitor의 모든 속성을 동기화하여 체크할 수 있습니다.이것에 의해, 원래의 약속의 상태가 추적됩니다.다음은 모니터링되는 약속의 세 가지 가능한 해결 방법을 보여주는 테스트 스크립트입니다.
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();
변수를 사용하여 상태를 저장하고 해당 변수를 수동으로 설정한 후 해당 변수를 체크할 수 있습니다.
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 패키지를 사용하여 (위험한 해킹 없이) 네이티브 약속을 동기화할 수 있게 되었습니다.
이것 때문에 꾸러미를 만들었어요.여기 있는 대부분의 다른 답변과 달리, 그것은 처리되지 않은 거절을 삼키지 않습니다.
npm install p-state
import timers from 'timers/promises';
import {promiseStateSync} from 'p-state';
const timeoutPromise = timers.setTimeout(100);
console.log(promiseStateSync(timeoutPromise));
//=> 'pending'
await timeoutPromise;
console.log(promiseStateSync(timeoutPromise));
//=> 'fulfilled'
해킹을 필요로 하지 않는 가장 간단한 해결책 중 하나를 생각해 낸 사람은 없는 것 같습니다.
- 약속이 실행 중임을 나타내는 변수를 정의합니다.
.finally
변수를 false로 설정하는 약속에 대한 절(약속 작성 후 언제든지 실행할 수 있습니다)- 그 후 코드에서 상기 변수가 참인지 거짓인지 확인하면 Promise가 아직 실행 중인지 확인할 수 있습니다.
여부뿐만 도 .finally
덧붙이다.then
a. a. a..catch
변수를 "syslog" 또는 "syslog"로 설정하는 절.
유일한 단점은 약속이 이미 종료된 경우 구를 추가할 때 상태 변수가 바로(동기적으로) 설정되지 않는다는 것입니다.따라서 약속 작성 후 가장 빠른 위치에 추가하는 것이 좋습니다.
예:
async function worker(){
// wait a very short period of time
await (new Promise(resolve => setTimeout(resolve, 100)))
//...
}
const w1=worker()
let w1_running=true
w1.finally( ()=> {w1_running=false});
//...
//Then check if it's running
(async ()=>{
while(true){
if (w1_running) {
console.log("Still Busy :(")
} else {
console.log("All done :)")
break
}
await (new Promise(resolve => setTimeout(resolve, 10)))
}
})()
// Note we need some async action started otherwise the event loop would never reach the code in the function `worker` or in the `.finally` clause
Queryable Promise의 보다 구체화된 버전을 소개합니다.이것에 의해, 최초의 해결 후에 체인을 해 캐치 할 수 있게 되어, 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>
2019:
은 내가 있는 와 같다.thenable
임의의 super thin wrapper are asponside promise.
const sleep = (t) => new Promise(res => setTimeout(res,t));
const sleeping = sleep(30);
function track(promise){
let state = 'pending';
promise = promise.finally( _=> state ='fulfilled');
return {
get state(){return state},
then: promise.then.bind(promise), /*thentable*/
finally:promise.finally.bind(promise),
catch:promise.catch.bind(promise),
}
}
promise = track(sleeping);
console.log(promise.state) // pending
promise.then(function(){
console.log(promise.state); // fulfilled
})
하면 돼요.
extend
Promise 클래스에서는 쿼리 가능한 Promise 클래스를 새로 만듭니다.
수 . 를 들어, 만의 서브클래스를 만들 수 있습니다.QueryablePromise
로 사용 가능한 "Native" 에서 Promise
, 클래스, 클래스, 클래스, 클래스, 클래스, 클래스, 클래스, 클래스, 클래스, 클래스, 클래스, 클래스, 클래스, 클래스, 클래스, 클래스.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)
★★★★★★★★★★★★★★process.binding('util').getPromiseDetails
undefined
16! 16! 16! 16! 번 on 。
벤치마크:
후보:
/**
* 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
론. 뻔. obviously. obviously.isPromisePending1()
8~) 단, 할 수 없습니다(경고 참조).그러나 노드 16에서는 사용할 수 없습니다(위 경고 참조).
ES7 Experimental을 사용하는 경우 비동기 기능을 사용하여 듣고 싶은 약속을 쉽게 포장할 수 있습니다.
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 패키지, 약속-value를 작성했다. 이 패키지는 약속 포장지를 제공한다.resolved
삭제:
https://www.npmjs.com/package/promise-value
또한 약속 값(또는 오류)에 대한 동기 액세스도 제공합니다.확장 패턴이 아닌 랩에 따라 Promise 개체 자체는 변경되지 않습니다.
좀 오래된 질문인데 저도 비슷한 걸 하려고 했어요.나는 n명의 노동자를 계속 일하게 할 필요가 있다.그들은 약속으로 구성되어 있다.검사하여 해결되었는지, 거부되었는지 또는 아직 보류 중인지 확인해야 합니다.해결된 경우 값이 필요하고 거부된 경우 문제를 수정하거나 보류 중인 경우 값이 필요합니다.해결되거나 거부된 경우 n개의 작업을 계속 진행하려면 다른 작업을 시작해야 합니다.Promise로 어떻게 해야 할지 모르겠어요.all 또는 Promise.race를 선택합니다.배열로 계속 작업하고 있는데 삭제할 방법을 찾을 수 없습니다.그래서 나는 노동자를 만들어 내는데
필요에 따라 해결하거나 거부하는 약속을 반환하는 약속 생성 기능이 필요합니다.약속이 무엇을 하고 있는지 알기 위해 프레임워크를 설정하는 함수에 의해 호출됩니다.
아래 코드에서는 생성자가 set Timeout에 따라 약속을 반환합니다.
여기 있어요.
//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는 약속과 그 상태와 반환된 값을 포함하는 개체를 반환합니다.
다음 코드는 상태를 테스트하고 새로운 워커를 생성하여 실행 중인 워커를 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 이 답변에서는 그다지 많지 않지만, 비슷한 주제에 대해 다른 사람이 "당신은 이해하지 못한다"거나 "그렇게 되는 것이 아니다"라고 말하는 것을 싫어합니다.저는 일반적으로 질문자가 그들이 무엇을 원하는지 알고 있다고 생각합니다.더 좋은 방법을 제안하는 것은 좋습니다.약속의 효과에 대한 인내심 있는 설명도 좋을 것입니다.
많은 답변이 있는 오래된 질문이지만, 내가 생각하는 가장 간단한 해결책은 아무것도 제시하지 않는 것 같다: 약속의 해결/거부에 대한 불 지표를 설정하는 것이다.
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);
은 ★★★입니다.Future
사용하는 패턴: (https://github.com/Smallscript-Corp)
- 를 유효하게 하다
sync
★★★★★★★★★★★★★★★★★」async
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
다음으로 동기 및 비동기 기능을 사용하여 해결할 수 있는 미래값 인스턴스를 작성할 수 있습니다.이 인스턴스는 이벤트 처리를 균일하게 할 수 있습니다.
이를 사용하여 다음과 같은 패턴을 작성할 수 있습니다.
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))
}
이 솔루션은 간단하고 네이티브 약속을 계속 사용할 수 있지만 유용한 동기 체크를 추가할 수 있습니다.그리고 약속 도서관을 다 볼 필요도 없었어요.
경고: 이것은 동기구조를 확인하기 전에 약속을 실행할 수 있도록 현재 실행 스레드에 일종의 중단이 있는 경우에만 작동합니다.그 때문에, 당초의 생각 이상으로 유용성이 한정되어 있습니다.-아직도 제 사용 예에 도움이 되고 있습니다(이 점을 지적해 주신 벤자신의 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);
ES6의 약속이 이행되었는지, 이행되었는지, 이행되었는지, 이행되었는지 여부를 판단할 수 있는 방법이 있습니까?
언급URL : https://stackoverflow.com/questions/30564053/how-can-i-synchronously-determine-a-javascript-promises-state
'source' 카테고리의 다른 글
목록 항목의 역순 (0) | 2022.10.27 |
---|---|
jQuery 이벤트 키 누르기:어떤 키를 눌렀습니까? (0) | 2022.10.27 |
MySQL: #126: 테이블에 대한 잘못된 키 파일 (0) | 2022.10.27 |
구성 및 라이브러리 파일을 사용하여 MySQL을 완전히 제거하려면 어떻게 해야 합니까? (0) | 2022.10.27 |
JavaScript에서 Blob을 파일로 변환하는 방법 (0) | 2022.10.27 |