Promise에서 여러 값을 올바르게 반환하는 방법은 무엇입니까?
최근에 특정 상황에 몇 번 부딪 쳤는데 제대로 해결하는 방법을 몰랐습니다. 다음 코드를 가정하십시오.
somethingAsync()
.then( afterSomething )
.then( afterSomethingElse )
function afterSomething( amazingData ) {
return processAsync( amazingData );
}
function afterSomethingElse( processedData ) {
}
나는에 대한 액세스를 갖고 싶어 할 경우 지금은 상황이 발생할 수도 amazingData
에서 afterSomethingElse
.
한 가지 분명한 해결책은에서 배열이나 해시를 반환하는 것입니다 afterSomething
. 왜냐하면 함수에서 하나의 값만 반환 할 수 있기 때문입니다. 그러나 afterSomethingElse
문서화하고 이해하기가 훨씬 쉬워 보이기 때문에 두 개의 매개 변수를 받아들이고 마찬가지로 호출하는 방법이 있는지 궁금합니다 .
나는 Q.spread
내가 원하는 것과 비슷한 일을하는이 있기 때문에이 가능성에 대해서만 궁금 합니다.
함수에서 여러 값을 반환 할 수없는 것처럼 여러 속성으로 promise를 해결할 수 없습니다 . promise는 개념적으로 시간 경과에 따른 값을 나타내므로 복합 값을 나타낼 수는 있지만 promise에 여러 값을 넣을 수는 없습니다.
Promise는 본질적으로 단일 값으로 해결됩니다. 이것은 Q 작동 방식, Promises / A + 사양 작동 방식 및 추상화 작동 방식의 일부입니다.
가장 가까운 방법은 Q.spread
배열을 사용 하고 반환하거나 지원되거나 BabelJS와 같은 트랜스 파일 도구를 사용하려는 경우 ES6 구조화를 사용하는 것입니다.
프라 미스 체인 아래로 컨텍스트를 전달하는 것에 대해서는 Bergi의 우수한 표준을 참조하십시오 .
하나의 값만 전달할 수 있지만 다음과 같이 여러 값이있는 배열 일 수 있습니다.
function step1(){
let server = "myserver.com";
let data = "so much data, very impresive";
return Promise.resolve([server, data]);
}
다른 측면에서, 당신은 사용할 수 있습니다 destructuring 개별 값을 얻을 수 ES2015에 대한 표현.
function step2([server, data]){
console.log(server); // print "myserver.com"
console.log(data); // print "so much data, very impresive"
return Promise.resolve("done");
}
두 약속을 모두 호출하고 연결합니다.
step1()
.then(step2)
.then((msg)=>{
console.log(msg); // print "done"
})
두 값을 모두 포함하는 객체를 반환 할 수 있습니다. 문제는 없습니다.
또 다른 전략은 가치를 전달하는 대신 클로저를 통해 유지 하는 것입니다.
somethingAsync().then(afterSomething);
function afterSomething(amazingData) {
return processAsync(amazingData).then(function (processedData) {
// both amazingData and processedData are in scope here
});
}
부분적으로 인라인 된 형식이 아닌 완전히 인라인 된 형식 (동등하고 틀림없이 더 일관성이 있음) :
somethingAsync().then(function (amazingData) {
return processAsync(amazingData).then(function (processedData) {
// both amazingData and processedData are in scope here
});
}
할 수있는 두 가지, 객체 반환
somethingAsync()
.then( afterSomething )
.then( afterSomethingElse );
function processAsync (amazingData) {
//processSomething
return {
amazingData: amazingData,
processedData: processedData
};
}
function afterSomething( amazingData ) {
return processAsync( amazingData );
}
function afterSomethingElse( dataObj ) {
let amazingData = dataObj.amazingData,
processedData = dataObj.proccessedData;
}
범위를 사용하십시오!
var amazingData;
somethingAsync()
.then( afterSomething )
.then( afterSomethingElse )
function afterSomething( returnedAmazingData ) {
amazingData = returnedAmazingData;
return processAsync( amazingData );
}
function afterSomethingElse( processedData ) {
//use amazingData here
}
여기에 당신이해야한다고 생각하는 방법이 있습니다.
체인 분할
두 함수 모두 amazingData를 사용 하므로 전용 함수에 두는 것이 좋습니다. 나는 일반적으로 일부 데이터를 재사용하고 싶을 때마다 그렇게하므로 항상 함수 인수로 존재합니다.
귀하의 예제가 일부 코드를 실행 중이므로 모두 함수 내에서 선언되었다고 가정합니다. 나는 그것을 toto () 라고 부를 것 입니다. 그런 다음 afterSomething () 과 afterSomethingElse () 둘 다 실행하는 또 다른 함수를 갖게됩니다 .
function toto() {
return somethingAsync()
.then( tata );
}
일반적으로 Promise를 사용하는 방법이므로 return 문을 추가 했음을 알 수 있습니다. 필요한 경우 계속 연결할 수 있도록 항상 promise를 반환합니다. 여기에서 somethingAsync () 는 amazingData 를 생성 하고 새 함수 내부의 모든 곳에서 사용할 수 있습니다.
이제이 새 함수는 일반적으로 processAsync ()도 비동기 에 따라 달라집니다 .
비동기가 아닌 processAsync
processAsync () 가 비동기가 아닌 경우 상황을 지나치게 복잡하게 만들 이유 가 없습니다. 오래된 좋은 순차 코드가 그것을 만들 것입니다.
function tata( amazingData ) {
var processed = afterSomething( amazingData );
return afterSomethingElse( amazingData, processed );
}
function afterSomething( amazingData ) {
return processAsync( amazingData );
}
function afterSomethingElse( amazingData, processedData ) {
}
afterSomethingElse () 가 비동기 작업을 수행 하는지 여부는 중요 하지 않습니다. 그럴 경우 약속이 반환되고 체인이 계속 될 수 있습니다. 그렇지 않은 경우 결과 값이 반환됩니다. 그러나 함수가 then () 에서 호출되기 때문에 값은 어쨌든 (적어도 원시 Javascript에서) promise로 래핑됩니다.
processAsync 비동기
경우 processAsync ()가 비동기 코드는 약간 다를 것입니다. 여기서 우리는 afterSomething () 과 afterSomethingElse () 가 다른 곳에서는 재사용되지 않을 것이라고 생각합니다.
function tata( amazingData ) {
return afterSomething()
.then( afterSomethingElse );
function afterSomething( /* no args */ ) {
return processAsync( amazingData );
}
function afterSomethingElse( processedData ) {
/* amazingData can be accessed here */
}
}
afterSomethingElse ()의 이전과 동일합니다 . 비동기 일 수도 있고 아닐 수도 있습니다. 약속이 반환되거나 해결 된 약속으로 래핑 된 값이 반환됩니다.
Your coding style is quite close to what I use to do, that is why I answered even after 2 years. I am not a big fan of having anonymous functions everywhere. I find it hard to read. Even if it is quite common in the community. It is as we replaced the callback-hell by a promise-purgatory.
I also like to keep the name of the functions in the then short. They will only be defined locally anyway. And most of the time they will call another function defined elsewhere - so reusable - to do the job. I even do that for functions with only 1 parameter, so I do not need to get the function in and out when I add/remove a parameter to the function signature.
Eating example
Here is an example:
function goingThroughTheEatingProcess(plenty, of, args, to, match, real, life) {
return iAmAsync()
.then(chew)
.then(swallow);
function chew(result) {
return carefullyChewThis(plenty, of, args, "water", "piece of tooth", result);
}
function swallow(wine) {
return nowIsTimeToSwallow(match, real, life, wine);
}
}
function iAmAsync() {
return Promise.resolve("mooooore");
}
function carefullyChewThis(plenty, of, args, and, some, more) {
return true;
}
function nowIsTimeToSwallow(match, real, life, bobool) {
}
Do not focus too much on the Promise.resolve(). It is just a quick way to create a resolved promise. What I try to achieve by this is to have all the code I am running in a single location - just underneath the thens. All the others functions with a more descriptive name are reusable.
The drawback with this technique is that it is defining a lot of functions. But it is a necessary pain I am afraid in order to avoid having anonymous functions all over the place. And what is the risk anyway: a stack overflow? (joke!)
Using arrays or objects as defined in other answers would work too. This one in a way is the answer proposed by Kevin Reid.
You can also use bind() or Promise.all(). Note that they will still require you to split your code.
using bind
If you want to keep your functions reusable but do not really need to keep what is inside the then very short, you can use bind().
function tata( amazingData ) {
return afterSomething( amazingData )
.then( afterSomethingElse.bind(null, amazingData) );
}
function afterSomething( amazingData ) {
return processAsync( amazingData );
}
function afterSomethingElse( amazingData, processedData ) {
}
To keep it simple, bind() will prepend the list of args (except the first one) to the function when it is called.
using Promise.all
In your post you mentionned the use of spread(). I never used the framework you are using, but here is how you should be able to use it.
Some believe Promise.all() is the solution to all problems, so it deserves to be mentioned I guess.
function tata( amazingData ) {
return Promise.all( [ amazingData, afterSomething( amazingData ) ] )
.then( afterSomethingElse );
}
function afterSomething( amazingData ) {
return processAsync( amazingData );
}
function afterSomethingElse( args ) {
var amazingData = args[0];
var processedData = args[1];
}
You can pass data to Promise.all() - note the presence of the array - as long as promises, but make sure none of the promises fail otherwise it will stop processing.
And instead of defining new variables from the args argument, you should be able to use spread() instead of then() for all sort of awesome work.
Simply make an object and extract arguments from that object.
let checkIfNumbersAddToTen = function (a, b) {
return new Promise(function (resolve, reject) {
let c = parseInt(a)+parseInt(b);
let promiseResolution = {
c:c,
d : c+c,
x : 'RandomString'
};
if(c===10){
resolve(promiseResolution);
}else {
reject('Not 10');
}
});
};
Pull arguments from promiseResolution.
checkIfNumbersAddToTen(5,5).then(function (arguments) {
console.log('c:'+arguments.c);
console.log('d:'+arguments.d);
console.log('x:'+arguments.x);
},function (failure) {
console.log(failure);
});
Whatever you return from a promise will be wrapped into a promise to be unwrapped at the next .then()
stage.
It becomes interesting when you need to return one or more promise(s) alongside one or more synchronous value(s) such as;
Promise.resolve([Promise.resolve(1), Promise.resolve(2), 3, 4])
.then(([p1,p2,n1,n2]) => /* p1 and p2 are still promises */);
In these cases it would be essential to use Promise.all()
to get p1
and p2
promises unwrapped at the next .then()
stage such as
Promise.resolve(Promise.all([Promise.resolve(1), Promise.resolve(2), 3, 4]))
.then(([p1,p2,n1,n2]) => /* p1 is 1, p2 is 2, n1 is 3 and n2 is 4 */);
You can check Observable represented by Rxjs, lets you return more than one value.
'program tip' 카테고리의 다른 글
PostgreSQL 함수 매개 변수로서의 테이블 이름 (0) | 2020.11.11 |
---|---|
iOS7의 UIActivityViewController에서 표시 될 때 메일 작성기에서 보내기 및 취소 단추의 텍스트 색상을 설정할 수 없습니다. (0) | 2020.11.11 |
iOS 10 / Xcode 8의 장치에서 NSLog가 잘리는 것처럼 보입니까? (0) | 2020.11.11 |
응용 프로그램이 화면 방향 변경을 무시하도록하는 방법은 무엇입니까? (0) | 2020.11.11 |
Android의 여러 MIME 유형 (0) | 2020.11.11 |