일. 직렬 태스크 큐 구현
태스크 큐란 A 가 완료되면 B 를 호출하고, B 가 완료되면 C 를 호출하는 것을 말합니다 (여기서 ABC 는 모두 비동기 작업을 나타냅니다)... 이전에는 콜백을 중첩하는 방식이었으며, 코드는 다음과 같았습니다:
taskA(data1, function(res) {
if (res.state === OK) {
taskB(data2, function(res) {
if (res.state === OK) {
taskC(data3, function(res) {
if (res.state === OK) {
// ...
}
else {
// err3
}
});
}
else {
// err2
}
});
}
else {
// err1
}
});
각 단계마다 오류가 발생할 수 있으며 (err1, err2, err3...), 오류 처리도 다를 수 있습니다. 코드 구조는 매우 비대해지고 (제어 불가능하게 "수평으로 발전"하여 결국 "한 덩어리"의 코드가 됨), 매우 지저분해집니다. 각 단계가 비동기 + 콜백이기 때문에 각 callback 을 분리하기가 매우 어렵습니다.
Promise 의 가장 두드러진 효과는 이러한 "콜백 피라미드"를 제거한다는 것이며, 코드는 더 이상 수평으로 발전하지 않습니다:
// taskX 는 모두 Promise 객체를 반환
taskA(data1).then(
taskB(data2),
errHandler1
).then(
taskC(data3),
errHandler2
).then(
displayData,
errHandler3
);
taskA 와 taskB 의 오류 처리가 동일하다면 더 간단하게 작성할 수 있습니다:
// taskX 는 모두 Promise 객체를 반환
taskA(data1).then(taskB(data2)).then(
taskC(data3),
errHandler12
).then(
displayData,
errHandler3
);
오류를 통합해서 처리하고 싶다면 이렇게 할 수 있습니다:
// taskX 는 모두 Promise 객체를 반환
taskA(data1).then(taskB(data2)).then(taskC(data3)).then(displayData).catch(errHandler);
// 다음과 동일
taskA(data1).then(taskB(data2)).then(taskC(data3)).then(displayData, errHandler);
체인 호출 + 오류 자동 뒤로 던지기로 인해 작성하기도 좋고 읽기도 좋습니다.
이. 직렬 태스크 파이프라인 구현
태스크 파이프라인이란 현재 작업의 출력을 다음 작업의 입력으로 사용할 수 있어 데이터 파이프라인을 형성하는 것을 말합니다. jQuery 코드는 다음과 같습니다:
$.post(url1, data, function(res) {
if (res.state === OK) {
$.post(url2, res.data, function(res) {
if (res.state === OK) {
$.post(url3, res.data, function(res) {
if (res.state === OK) {
// ...
}
else {
// err3
}
});
}
else {
// err2
}
});
}
else {
// err1
}
});
실제 시나리오에서 매우 흔합니다. 예를 들어 url1 에서 매개변수 userId 를 가져온 후, 이를拿到하여 url2 에서 서드파티 openId 를 교환하고, 마지막으로 url3 에서 orderList 를 교환한 후 결과를 사용자에게 표시합니다. 이러한 로직은 모두 자연스러운 태스크 파이프라인입니다.
Promise 를 사용하면 이렇게 구현할 수 있습니다:
new Promise(function(resolve, reject) {
resolve(1);
}).then(function(res) {
return new Promise(function(resolve, reject) {
resolve(res + 1);
});
}).then(function(res) {
return new Promise(function(resolve, reject) {
resolve(res + 1);
});
}).then(function(res) {
console.log(res);
});
// => 3
P.S. jQuery 의 $.when() 은 일종의 Promise 구현이지만 Promise A+ 사양과는 약간의 차이가 있습니다. 자세한 내용은 jQuery deffered 와 promise 객체 메서드 를 참조하세요.
삼. 실행 시에야 실행 순서를 확인할 수 있는 직렬 작업 처리
A, B, C 세 개의 작업이 있다고 가정합니다. 실행 순서는 불확실하며, BCA, BAC 등이 될 수 있습니다. 실행 시에야 비로소 세자의 실행 순서가 결정되지만, 순서가 결정되면 즉시 직렬로 실행해야 합니다.
이 경우 콜백 중첩은 더 이상 충족시킬 수 없습니다. 각 순서에 대해 하나의 콜백 중첩이 필요하기 때문입니다. 우리는 콜백을 자유롭게 조합할 수 있는 메커니즘이 필요합니다. 예를 들어 Promise 와 같은:
var tasks = getOrderedTasks();
var p = tasks[0];
tasks.forEach(function(item, index) {
p.then(item);
});
이렇게 작성하면 부작용으로 파이프라인이 없어집니다 (작업의 출력을 다음 작업의 입력으로 전달할 수 없게 됨). 하지만 문제없습니다. 쉽게 수정할 수 있습니다:
function catchFuture(future) {
// future 를 처리/전달
// ...
console.log('catchFuture: ' + future);
}
var tasks = getOrderedTasks();
var p = tasks[0];
tasks.forEach(function(item, index) {
// p.then(item);
p.then(item.then(catchFuture));
});
아직 댓글이 없습니다