JavaScript Promise의 상태를 동 기적으로 어떻게 확인할 수 있습니까?
순수한 JavaScript Promise (내장 구현 또는 폴리 필)가 있습니다.
var promise = new Promise(function (resolve, reject) { /* ... */ });
로부터 사양 , 약속은 다음 중 하나 일 수 있습니다 :
- '정착'및 '해결'
- '정착'및 '거부'
- '보류 중'
약속을 동 기적으로 조사하고 다음을 결정하려는 유스 케이스가 있습니다.
약속이 정 해졌습니까?
그렇다면 약속이 해결 되었습니까?
#then()
약속 변경 상태 후에 작업이 비동기 적으로 수행되도록 예약 하는 데 사용할 수 있다는 것을 알고 있습니다 . 이 작업을 수행하는 방법을 묻지 않습니다.
이 질문은 구체적 으로 Promise의 상태 에 대한 동기식 심문에 관한 것 입니다. 어떻게하면 되나요?
기본 JavaScript 약속에 대한 동기 검사 API는 없습니다. 기본 약속으로는 불가능합니다. 사양에서는 이러한 방법을 지정하지 않습니다.
Userland 라이브러리가이를 수행 할 수 있으며 v8과 같은 특정 엔진을 대상으로하고 플랫폼 코드에 액세스 할 수있는 경우 (즉, 핵심 코드를 작성할 수있는 경우) 개인 도구와 같은 특정 도구를 사용하여이를 달성 할 수 있습니다. . 그것은 userland가 아니라 매우 구체적입니다.
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;
}
아니요, 동기화 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.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
파이어 폭스 (크롬 순서를 유지) 와이 테스트의 결과
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 : 레벨 2
네이티브 메소드가 제공 될 때까지 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
}
이 기본 기능이 없다는 것은 실제로 성가신 일입니다. 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 };
};
업데이트 : 2019
Bluebird.js는 다음을 제공합니다. http://bluebirdjs.com/docs/api/isfulfilled.html
var Promise = require("bluebird");
let p = Promise.resolve();
console.log(p.isFulfilled());
자신 만의 래퍼를 만들고 싶다면 여기에 좋은 블로그 가 있습니다.
JavaScript는 단일 스레드이기 때문에 사양에 넣는 것을 정당화하기에 충분한 일반적인 사용 사례를 찾기가 어렵습니다. 약속이 해결되었는지 알 수있는 가장 좋은 곳은 .then ()입니다. 약속이 꽉 찼는 지 테스트하면 폴링 루프가 만들어져 잘못된 방향 일 가능성이 큽니다.
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"]
이 답변에 처음 도달했을 때, 이것이 내가 찾던 사용 사례입니다.
이런 방식으로 약속을 감쌀 수 있습니다
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;
}
노드에서 문서화되지 않은 내부 라고 말하십시오. 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 내부를 사용하며 경고없이 변경 될 수 있습니다.
노드에서을 사용하여 약속의 상태를 동 기적으로 결정할 수 있습니다 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
할 수있는 것은 변수를 사용하여 상태를 저장하고 수동으로 상태를 해당 변수로 설정 한 다음 해당 변수를 확인하는 것입니다.
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에 메서드를 추가 할 수 있습니다. 다음과 같이 보입니다 :
편집 : 여기에있는 대부분의 답변과 같이 첫 번째 솔루션이 제대로 작동하지 않습니다. 비동기 함수 ".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;
};
}
모든 약속에서 사용할 수 있습니다. 예를 들어:
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
보다 포괄적 인 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
플래그 를 제공합니다 .
https://www.npmjs.com/package/promise-value
또한 약속 값 (또는 오류)에 대한 동기 액세스를 제공합니다. 이것은 확장 패턴이 아니라 랩을 따라 Promise 오브젝트 자체를 변경하지 않습니다.
이것은 오래된 질문이지만 비슷한 것을하려고했습니다. 나는 n 명의 노동자를 계속 유지해야합니다. 그들은 약속으로 구성되어 있습니다. 스캔하여 해결, 거부 또는 보류 중인지 확인해야합니다. 해결되면 값이 필요합니다. 거부되면 문제를 해결하거나 보류중인 작업을 수행하십시오. 해결되거나 거부되면 계속 진행하기 위해 다른 작업을 시작해야합니다. Promise.all 또는 Promise.race를 사용하여 약속을 배열로 유지하면서 삭제할 수있는 방법을 찾을 수 없습니다. 트릭을 수행하는 작업자를 만듭니다.
필요에 따라 해결하거나 거부하는 약속을 반환하는 약속 생성기 함수가 필요합니다. 약속이 무엇을하는지 알 수 있도록 프레임 워크를 설정하는 함수에 의해 호출됩니다.
아래 코드에서 생성기는 단순히 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에서 테스트
BTW이 답변에는 그다지 많지 않지만 비슷한 주제에 관한 다른 사람들에게는 누군가가 "당신이 이해하지 못함"또는 "그렇지 않다"고 말할 때 싫어합니다. 더 나은 방법을 제안하는 것이 좋습니다. 약속이 어떻게 작동하는지에 대한 환자의 설명도 좋습니다.
await
관용적 프로토 타이핑과 함께 @ jib 's answer 사용법 .
Object.defineProperty(Promise.prototype, "state", {
get: function(){
const o = {};
return Promise.race([this, o]).then(
v => v === o ? "pending" : "resolved",
() => "rejected");
}
});
// usage:
(async () => {
console.log(await <Your Promise>.state);
console.log(await Promise.resolve(2).state); // "resolved"
console.log(await Promise.reject(0).state); // "rejected"
console.log(await new Promise(()=>{}).state); // "pending"
});
이 비동기 함수는 동기화 된 함수처럼 "거의"즉시 실행됩니다 (또는 실제로는 즉시있을 수도 있음).
이 솔루션이 간단하고 기본 약속을 계속 사용할 수는 있지만 유용한 동기 검사를 추가 할 수 있다는 것을 알았습니다. 또한 전체 약속 라이브러리를 가져올 필요가 없었습니다.
주의 사항 : 이것은 동기 실행 구문을 확인하기 전에 약속을 실행할 수 있도록 현재 실행 스레드에 일종의 중단이있는 경우에만 작동합니다. 그것은 내가 처음 생각했던 것보다 훨씬 제한된 유용성을 만듭니다. 그러나 여전히 유스 케이스에 유용합니다 ( 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 에서 답을 기반으로 하는 방법이 있습니까? ES6 약속이 이행 / 거부 / 해결되었는지를 알려주시겠습니까?
'programing tip' 카테고리의 다른 글
os.walk에서 디렉토리 제외 (0) | 2020.07.06 |
---|---|
Kotlin의 목록 유형과 배열 유형의 차이점 (0) | 2020.07.06 |
JAX-WS, Axis2 및 CXF의 차이점 (0) | 2020.07.05 |
cscope 또는 ctags 왜 다른 것을 선택합니까? (0) | 2020.07.05 |
R 메모리 관리 / 크기 n Mb의 벡터를 할당 할 수 없음 (0) | 2020.07.05 |