Back Ground

JavaScript - Promise 본문

Javascript

JavaScript - Promise

Back 2019. 12. 19. 00:31

 

 

Promise가 무엇인가?

 

프로미스는 자바스크립트 비동기처리에 사용되는 객체.

 

여기서 자바스크립트의 비동기 처리

'특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 자바스크립트 특성'을 위미한다.

 

 

Promise 코드 - 기초

 

그럼 프로미스가 어떻게 동작하는지 이해하기 위해 예제 코드를 살펴본다.

 

[간단한 ajax 통신코드 - Callback을 사용한 경우] 

function getData(callbackFunc) {
  $.get('url 주소/products/1', function (response) {
    callbackFunc(response); // 서버에서 받은 데이터 response를 callbackFunc() 함수에 넘겨줌
  });
}

getData(function (tableData) {
  console.log(tableData); // $.get()의 response 값이 tableData에 전달됨
});

 위 코드를 제이쿼리 ajax통신을 이용하여

지정한 url에서 1번 상품데이터를 받아오는 코드이다. 

비동기 처리를 위해 프로미스 대신에 콜백 함수를 이용했다.

 

 

[Promise를 사용한 경우]

function getData(callback) {
  // new Promise() 추가
  return new Promise(function (resolve, reject) {
    $.get('url 주소/products/1', function (response) {
      // 데이터를 받으면 resolve() 호출
      resolve(response);
    });
  });
}

// getData()의 실행이 끝나면 호출되는 then()
getData().then(function (tableData) {
  // resolve()의 결과 값이 여기로 전달됨
  console.log(tableData); // $.get()의 reponse 값이 tableData에 전달됨
});

콜백 함수로 처리하던 구조에서 new Promise(), resolve(), then()와 같은 프로미스 API를 사용한 구조로 바뀌었다.

여기서 new Promise()는 좀 이해가 가겠는데 resolve(), then()은 뭐하는 함수일까..

 

 

프로미스의 3가지 상태

프로미스를 사용할 때 알아야 하는 가장 기본적인 개념이 바로 프로미스 상태(status) 이다.

여기서 말하는 상태란 프로미스의 처리 과정을 의미한다.

new Promise()로 프로미스를 생성하고 종료될 때까지 3가지 상태를 갖는다.

 

  • Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태
  • Fulfilled(이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
  • Rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태

 

Pending(대기)

먼저 아래와 같이 new Promise() 메서드를 호출하면 Pending(대기) 상태가 된다.

new Promise();

이렇게 new Promise()메서드를 호출할 때 콜백 함수의 인자로 resolve, reject에 접근할 수 있다.

new Promise(function(resolve, reject){
 //...
});

 

Fulfilled(이행)

여기서 콜백 함수의 인자 resolve를 아래와 같이 실행하면 Fulfilled(이행)상태가 된다. 

new Promise(function(resolve, reject){
	resolve();
});

그리고 이행 상태가 되면 아래와 같이 then()을 이용하여 처리 결과 값을 받을 수 있다.

function getData(){
 return new Promise(function(resolve, reject){
 	var data = 100;
    resolve(data);
 });
}

// resolve()의 결과값 data를 resolveData로 받음
getData().then(function(resolvedData){
 console.log(resolvedData); //100
});

프로미스의 '이행'상태를 좀 다르게 표현해보면 '완료'이다.

 

Rejected(실패)

new Promise()로 프로미스 객체를 생성하면 콜백 함수 인자로 resolve와 reject를 사용할 수 있다고 했다.

여기서 reject인자로 reject()메서드를 실행하면 Rejected(실패)상태가 된다.

new Promise(function (resolve, reject) {
  reject();
});

 그리고, 실패 상태가 되면 실패한 이유(실패 처리의 결과 값)를 catch()로 받을 수 있다.

function getData() {
  return new Promise(function (resolve, reject) {
    reject(new Error("Request is failed"));
  });
}

// reject()의 결과 값 Error를 err에 받음
getData().then().catch(function (err) {
  console.log(err); // Error: Request is failed
});
  • fulfilled (처리완료) - 작업성공
  • rejected (거부됨) - 작업 실패
  • pending (보류 됨) - 작업 시작 전
  • settled(해결 됨) - 처리완료 혹은 거부 됨
  1. 그림을 왼쪽부터 보자면 Promise가 하나 있고, Pending상태이다.
    아직 작업을 시작하지 않은 대기상태(보류)를 나타낸다.
  2. 작업을 진행 하다가 fulfill 혹은 reject상황으로 상태가 바뀐다.
    먼저 성공했다고 가정하면 fulfill상태가 되고 그 다음 과정인 then()이 호출된다.
    성공 되었으니 settled 상태가 되고,
    then함수 내에서 비동기 작업을 할 코드를 작성하면 된다.

  3. 프로미스가 1개라면 위의 2번 단계가 끝인데,
    만약 프로미스가 여러개 생성되어있고(a,b,c) 순차적으로 비동기작업을 진행해야 한다면
    a가 끝난 후 b프로미스를 return해준다.
    b프로미스는 a와 동일하게 fulfill 혹식 reject상태가 되고 성공,
    실패시 코드를 실행하게 된다.
    프로미스가 체이닝(연결)되면 하나하나 순차적으로 실행하게 된다.

프로미스 코드 - 쉬운 예제

먼저 ajax통신을 예제로 프로미스를 적용해보겠다.

function getData() {
  return new Promise(function (resolve, reject) {
    $.get('url 주소/products/1', function (response) {
      if (response) {
        resolve(response);
      }
      reject(new Error("Request is failed"));
    });
  });
}

// Fulfilled 또는 Rejected의 결과 값 출력
getData().then(function (data) {
  console.log(data); // response 값 출력
}).catch(function (err) {
  console.error(err); // Error 출력
});

위 코드는 서버에서 제대로 응답을 받아오면 resolve()메서드를 호출하고,

응답이 없으면 reject()메서드를 호출하는 예제이다.

호출된 메서드에 따라 then()이나 catch()로 분기하여 데이터 또는 오류를 출력한다.

 

 

여러 개의 프로미스 연결하기( Promise Chaining)

프로미스의 또 다른 특징은 여러 개의 프로미스를 연결하여 사용할 수 있다는 점이다.

앞 예제에서 then()메서드를 호출하고 나면 새로운 프로미스 객체가 반환된다.

따라서, 아래와 같이 코딩이 가능하다.

function getData() {
  return new Promise({
    // ...
  });
}

// then() 으로 여러 개의 프로미스를 연결한 형식
getData()
  .then(function (data) {
    // ...
  })
  .then(function () {
    // ...
  })
  .then(function () {
    // ...
  });

그러면 위의 형식을 참고하여 실제로 돌려볼 수 있는 예제를 살펴보겠다.

비동기 처리 예제에서 가장 흔하게 사용되는 setTimeout() API를 사용하였다.

new Promise(function(resolve, reject){
  setTimeout(function() {
    resolve(1);
  }, 2000);
})
.then(function(result) {
  console.log(result); // 1
  return result + 10;
})
.then(function(result) {
  console.log(result); // 11
  return result + 20;
})
.then(function(result) {
  console.log(result); // 31
});

 위 코드는 프로미스 객체를 하나 생성하고 setTimeout()을 이용해 2초 후에 resolve()를 호출하는 예제이다.

resolve()가 호출되면 프로미스가 대기 상태에서

이행 상태로 넘어가기 때문에 첫번째 .then()의 로직으로 넘어간다.

첫 번째 .then()에서는 이행된 결과 값 1을 받아서 10을 더한 후 그 다음 .then()으로 넘겨준다.

두 번째 .then()에서도 마찬가지로 바로 이전 프로미스의 결과 값 11을 받아서 20을 더하고 다음.then()으로 넘겨준다.

마지막 .then()에서 최종 결과 값 31을 출력한다.

 

실무에서 있을 법한 프로미스 연결 사례

실제 웹 서비스에서 있을 법한 사용자 로그인 인증 로직에 프로미스를 여러 개 연결해보겠다.

getData(userInfo)
  .then(parseValue)
  .then(auth)
  .then(diaplay);

위 코드는 페이지에 입력된 사용자 정보를 받아와 파싱, 인증 등의 작업을 거치는 코드를 나타내었다.

여기서 userInfo는 사용자 정보가 담긴 객체를 의미하고,

parseValue, auth, display는 각각 프로미스를 함수라고 가정했다. 

 

var userInfo = {
  id: 'test@abc.com',
  pw: '****'
};

function parseValue() {
  return new Promise({
    // ...
  });
}
function auth() {
  return new Promise({
    // ...
  });
}
function display() {
  return new Promise({
    // ...
  });
}

이 처럼 여러 개의 프로미스를 .then()으로 연결하여 처리할 수 있다.

 

프로미스의 에러 처리 방법

앞에서 살펴본 프로미스 예제는 코드가 항상 정상적으로 동작한다고 가정하고 구현한 예제이다.

실제 서비스를 구현하다 보면 네트워크 연결, 상태 코드 문제 등으로 인해 오류가 발생 할 수 있다.

따라서, 프로미스의 에러 처리방법에 대해서도 알고 있어야 한다.

 

에러 처리 방법에는 다음과 같이 2가지 방법이 있는다.

 

1. then()의 두 번째 인자로 에러를 처리하는 방법

getData().then(
  handleSuccess,
  handleError
);

 

2.catch()를 이용하는 방법

getData().then().catch();

 

위 2가지 방법 모두 프로미스의 reject() 메서드가 호출되어 실패 상태가 된 경우 실행된다.

간단하게 말해서 프로미스의 로직이 정상적으로 돌아가지 않는 경우 호출되는 거다.

function getData() {
  return new Promise(function (resolve, reject) {
    reject('failed');
  });
}

// 1. then()으로 에러를 처리하는 코드
getData().then(function () {
  // ...
}, function (err) {
  console.log(err);
});

// 2. catch()로 에러를 처리하는 코드
getData().then().catch(function (err) {
  console.log(err);
});

 

프로미스 에러 처리는 가급적 catch()로

앞에서 프로미스 에러 처리 방법 2가지를 살펴봤다.

개개인의 코딩 스타일에 따라서 then()의 두번째인자 처리할 수도 있고 catch()로 처리 할 수도 있겠지만

가급적 catch()로 에러를 처리하는게 더 효율적이다.

// then()의 두 번째 인자로는 감지하지 못하는 오류
function getData() {
  return new Promise(function (resolve, reject) {
    resolve('hi');
  });
}

getData().then(function (result) {
  console.log(result);
  throw new Error("Error in then()"); // Uncaught (in promise) Error: Error in then()
}, function (err) {
  console.log('then error : ', err);
});

getData()함수의 프로미스에서 resolve() 메서드를 호출하여 정상적으로 로직을 처리했지만,

then()의 첫 번째 콜백 함수 내부에서 오류가 나는 경우 오류를 제대로 잡아내지 못한다.

따라서 코드를 실행하면 아래와 같은 오류가 난다.

 

'에러를 잡지 못했습니다(Uncaught Error)' 로그

하지만 똑같은 오류를 catch()로 처리하면 다른 결과가 나온다.

// catch()로 오류를 감지하는 코드
function getData() {
  return new Promise(function (resolve, reject) {
    resolve('hi');
  });
}

getData().then(function (result) {
  console.log(result); // hi
  throw new Error("Error in then()");
}).catch(function (err) {
  console.log('then error : ', err); // then error :  Error: Error in then()
});

위 코드와 처리 결과는 다음 과같다.

발생한 에러를 성공적으로 콘솔에 출력한 모습

 

따라서, 더 많은 예외 처리 상황을 위해 프로미스의 끝에 가급적 catch()를 붙이기 바란다.

 

 

 

 

What is a Promise?

 

Promise is an object used for JavaScript asynchronous processing.

 

Here, what is asynchronous processing in JavaScript

It refers to the'JavaScript characteristic that executes the next code first without waiting for the execution of a specific code to be completed'.

 

 

Promise code-basics

 

So let's take a look at the example code to understand how Promise works.

 

[Simple ajax communication code-In case of using Callback] 

function getData(callbackFunc) {
  $.get('url adress/products/1', function (response) {
    callbackFunc(response); // Turns the data response received from the server to the callbackFunc() function
  });
}

getData(function (tableData) {
  console.log(tableData); // The response value of $.get() is delivered to tableData
});

 Use the above code to jquery ajax communication

This is a code that receives product data #1 from the designated url. 

For asynchronous processing, a callback function was used instead of a promise.

 

 

[In case of using Promise]

function getData(callback) {
  // new Promise() add
  return new Promise(function (resolve, reject) {
    $.get('url adress/products/1', function (response) {
      // if upon receiving the data resolve() response
      resolve(response);
    });
  });
}

// then() called when getData() finishes executing
getData().then(function (tableData) {
  // The result of resolve() is passed here
  console.log(tableData); // The response value of $.get() is passed to tableData.
});

The structure that used to be processed as a callback function has been changed to a structure that uses promise APIs such as new Promise(), resolve(), and then() .

Here, new Promise() makes sense, but what functions are resolve() and then() ?

 

 

The three states of Promise

The most basic concept you need to know when using promises is the promise status .

The state here refers to the process of Promise.

It creates a promise with new Promise() and has three states until it is closed.

 

  • Pending: Asynchronous processing logic has not yet completed
  • Fulfilled: Asynchronous processing is completed and Promise returns a result value.
  • Rejected: Asynchronous processing has failed or an error has occurred.

 

Pending

First, when the new Promise() method is called as shown below, it becomes the Pending state.

new Promise();

When calling the new Promise() method like this , you can access resolve and reject as arguments of the callback function.

new Promise(function(resolve, reject){
 //...
});

 

Fulfilled

Here, if you execute the argument resolve of the callback function as follows, it becomes a Fulfilled state. 

new Promise(function(resolve, reject){
	resolve();
});

And when the transition state is reached , you can use then() to receive the processing result value.

function getData(){
 return new Promise(function(resolve, reject){
 	var data = 100;
    resolve(data);
 });
}

// Receive the result data of resolve() as resolveData
getData().then(function(resolvedData){
 console.log(resolvedData); //100
});

Pro Miss "implementation" haebomyeon some other words the status "I'm done" a.

 

Rejected

It was said that if you create a promise object with new Promise() , you can use resolve and reject as callback function arguments.

Here, if you execute the reject() method with the reject argument, it becomes Rejected (failed).

new Promise(function (resolve, reject) {
  reject();
});

 And, when it becomes a failure state, the reason for the failure (the result value of the failure processing) can be received by catch() .

function getData() {
  return new Promise(function (resolve, reject) {
    reject(new Error("Request is failed"));
  });
}

// Receive the error result of reject() in err
getData().then().catch(function (err) {
  console.log(err); // Error: Request is failed
});
  • Fulfilled (processed)-work success
  • rejected-operation failed
  • pending-before starting work
  • settled (resolved)-processed or rejected
  1. Looking at the picture from the left, there is one Promise, and it is in the Pending state.
    It indicates a waiting state (pending) that has not started work yet .
  2. During the process, the status changes to a fulfillment or rejection situation.
    Assuming that it succeeds first, it is fulfilled , and then() is called.
    Now that it is successful, it becomes settled,
    and you can write code to do asynchronous work in the then function.

  3. If there is only one promise, step 2 above is over.
    If there are multiple promises (a, b, c) and you need to perform asynchronous work in sequence,
    b promise is returned after a ends.
    b Promise is the same as a, fulfilled or rejected, and the
    code is executed upon success or failure.
    When promises are chained (connected), they are executed one by one.

Promise code-an easy example

First, let's apply a promise using ajax communication as an example.

function getData() {
  return new Promise(function (resolve, reject) {
    $.get('url adress/products/1', function (response) {
      if (response) {
        resolve(response);
      }
      reject(new Error("Request is failed"));
    });
  });
}

// Print the result of Fulfilled or Rejected
getData().then(function (data) {
  console.log(data); // Response value output
}).catch(function (err) {
  console.error(err); // Error output
});

The code above calls the resolve() method when a response is properly received from the server ,

This is an example of calling the reject() method if there is no response .

Depending on the method called , it branches to then() or catch() to output data or errors.

 

 

Connecting multiple promises (promise chaining)

Another feature of Promise is that you can connect multiple Promises.

In the previous example, after calling the then() method, a new promise object is returned.

Therefore, coding is possible as follows.

function getData() {
  return new Promise({
    // ...
  });
}

// then() to concatenate multiple promises
getData()
  .then(function (data) {
    // ...
  })
  .then(function () {
    // ...
  })
  .then(function () {
    // ...
  });

Then, we will look at an example that can be actually run by referring to the above format.

The setTimeout() API, which is most commonly used in the asynchronous processing example, was used.

new Promise(function(resolve, reject){
  setTimeout(function() {
    resolve(1);
  }, 2000);
})
.then(function(result) {
  console.log(result); // 1
  return result + 10;
})
.then(function(result) {
  console.log(result); // 11
  return result + 20;
})
.then(function(result) {
  console.log(result); // 31
});

 The code above is an example of creating a promise object and calling resolve() 2 seconds later using setTimeout() .

When resolve() is called, the promise is waiting

Since we are going to the transition state, we move on to the logic of the first .then() .

The first .then() takes the value of 1, adds 10, and passes it to the next .then() .

Likewise in the second .then() , it takes 11, adds 20, and passes it to the next .then() .

In the last .then() , the final result is 31.

 

Promising connection example in practice

We will connect several promises to the user login authentication logic that would exist in an actual web service.

getData(userInfo)
  .then(parseValue)
  .then(auth)
  .then(diaplay);

The code above shows the code that receives the user information entered on the page and undergoes parsing and authentication.

Here, userInfo means an object containing user information,

parseValue , auth , and display each assumed a promise as a function. 

 

var userInfo = {
  id: 'test@abc.com',
  pw: '****'
};

function parseValue() {
  return new Promise({
    // ...
  });
}
function auth() {
  return new Promise({
    // ...
  });
}
function display() {
  return new Promise({
    // ...
  });
}

Like this, you can process multiple promises by connecting them with .then() .

 

Promise error handling method

The promise example discussed above is an example implemented under the assumption that the code always operates normally.

When implementing a real service, errors may occur due to network connectivity and status code problems.

Therefore, you must also know how to handle errors in Promise.

 

There are two methods of error handling as follows.

 

1. How to handle errors with the second argument of then()

getData().then(
  handleSuccess,
  handleError
);

 

2.How to use catch()

getData().then().catch();

 

Both of the above methods are executed when Promise's reject() method is called and it becomes a failure state.

Simply put, it is called when the logic of Promise does not work normally.

function getData() {
  return new Promise(function (resolve, reject) {
    reject('failed');
  });
}

// 1. The code that handles errors with then()
getData().then(function () {
  // ...
}, function (err) {
  console.log(err);
});

// 2. Code that handles errors with catch()
getData().then().catch(function (err) {
  console.log(err);
});

 

Promise error handling is possible with catch()

Previously, we looked at two ways to handle promise errors.

Depending on the coding style of each individual, the second argument of then() can be handled or catch() can be used.

It is more efficient to handle errors with catch() whenever possible.

// Error not detected by the second argument of then()
function getData() {
  return new Promise(function (resolve, reject) {
    resolve('hi');
  });
}

getData().then(function (result) {
  console.log(result);
  throw new Error("Error in then()"); // Uncaught (in promise) Error: Error in then()
}, function (err) {
  console.log('then error : ', err);
});

The logic was normally processed by calling the resolve() method in the promise of the getData() function.

If an error occurs inside the first callback function of then(), the error cannot be caught properly.

So, when I run the code, I get the following error.

 

Log'Uncaught Error'

However, handling the same error with catch() yields different results.

// Code to detect errors with catch()
function getData() {
  return new Promise(function (resolve, reject) {
    resolve('hi');
  });
}

getData().then(function (result) {
  console.log(result); // hi
  throw new Error("Error in then()");
}).catch(function (err) {
  console.log('then error : ', err); // then error :  Error: Error in then()
});

The above code and processing result are as follows.

The error that occurred was successfully printed to the console.

 

So, for more exception handling situations, add catch() at the end of the promise if possible.

Promiseは何ですか?

 

プロミスはJavaScriptの非同期処理に使用されるオブジェクト。

 

ここではJavaScriptの非同期処理

「特定のコードの実行が完了するまで待たずに、次のコードを最初に実行するJavaスクリプトの特性」を唯美する。

 

 

Promiseコード - 基礎

 

その後、プロミスがどのように動作するのかを理解するために、サンプルコードを見てみる。

 

[簡単なajax通信コード - Callbackを使用した場合] 

function getData(callbackFunc) {
  $.get('url アドレス/products/1', function (response) {
    callbackFunc(response); // サーバーから受信したデータresponseをcallbackFunc()関数に渡しズーム
  });
}

getData(function (tableData) {
  console.log(tableData); // $ .get()のresponse値がtableDataに渡さ
});

 上記のコードをジェイクエリajax通信を利用して

指定されたurlで1番の商品データを受けて来るコードである。 

非同期処理のためにプロミスの代わりにコールバック関数を利用した。

 

 

[Promiseを使用した場合]

function getData(callback) {
  // new Promise() 追加
  return new Promise(function (resolve, reject) {
    $.get('url 주소/products/1', function (response) {
      // データを受信すると、resolve()呼び出し
      resolve(response);
    });
  });
}

// getData()の実行が完了すると呼び出されるthen()
getData().then(function (tableData) {
  // resolve()の結果の値がここに転送される
  console.log(tableData); // $.get()のreponse値がtableDataに渡さ
});

コールバック関数で処理していた構造でnew Promise()、resolve()、then()のようなプロミスAPIを使用した構造に変わった。

ここnew Promise()は、いくつかの理解が行くのにresolve()、then()がやって関数だろう..

 

 

プロミスの3つの状態

プロミスを使用するときに知っておくべき最も基本的な概念は、まさにプロミス状態(status)である。

ここでいう状態とプロミスの処理を意味する。

new Promise()でプロミスを作成して終了するまでの3つの状態を持つ。

 

  • Pending(待機):非同期処理ロジックがまだ完了していない状態
  • Fulfilled(移行):非同期処理が完了されてプロミスが結果値を返してくれた状態
  • Rejected(失敗):非同期処理が失敗したり、エラーが発生した状態

 

Pending(待機)

まず、以下のようにnew Promise()メソッドを呼び出すと、Pending(待機)状態になる。

new Promise();

このようにnew Promise()メソッドを呼び出すときにコールバック関数の引数としてresolve、rejectにアクセスすることができる。

new Promise(function(resolve, reject){
 //...
});

 

Fulfilled(移行)

ここで、コールバック関数の引数resolveを以下のように実行すると、Fulfilled(移行)状態になる。 

new Promise(function(resolve, reject){
	resolve();
});

そして達成状態になると、以下のようにthen()を利用して、処理結果の値を取得することができる。

function getData(){
 return new Promise(function(resolve, reject){
 	var data = 100;
    resolve(data);
 });
}

// resolve()の結果の値dataをresolveDataに受け
getData().then(function(resolvedData){
 console.log(resolvedData); //100
});

プロミスの「履行」の状態を見て別の方法で表現してみると「完了」である。

 

Rejected(失敗)

new Promise()でプロミスオブジェクトを作成すると、コールバック関数の引数としてresolveとrejectを使用することができているとした。

ここでreject引数としてreject()メソッドを実行すると、Rejected(失敗)状態になる。

new Promise(function (resolve, reject) {
  reject();
});

 そして、失敗状態になると失敗した理由(失敗処理の結果値)をcatch()で取得することができる。

function getData() {
  return new Promise(function (resolve, reject) {
    reject(new Error("Request is failed"));
  });
}

// reject()の結果の値Errorをerrに受ける
getData().then().catch(function (err) {
  console.log(err); // Error: Request is failed
});
  • fulfilled(処理完了) - 作業成功
  • rejected(拒否) - 操作に失敗し
  • pending(保留) - ジョブの開始前
  • settled(解決される) - 処理完了、あるいは拒否されまし
  1. 図を左から見るとPromiseが一つあって、Pending状態である。
    まだ作業を開始していない待機状態(保留)を示す。
  2. 作業を進めている途中fulfillあるいはreject状況で状態が変わる。
    まず、成功したと仮定するとfulfill状態になって、その次の過程であるthen()が呼び出されます。
    成功したのでsettled状態となり、
    then関数内で非同期操作をするコードを記述すればよい。

  3. プロミスが1つであれば、上記の2回のステップが終了だが、
    もしプロミスが複数生成されていて、(a、b、c)順次非同期操作を行わなければなら
    aが終わった後、bプロミスをreturnしてくれる。
    bプロミスはaと同様にfulfillホクシクreject状態になって成功、
    失敗時のコードを実行することになる。
    プロミスがチェーン(接続)されると、一つ一つ順番に実行することになる。

プロミスコード - 簡単な例

まず、ajax通信を例にプロミスを適用してみよう。

function getData() {
  return new Promise(function (resolve, reject) {
    $.get('url アドレス/products/1', function (response) {
      if (response) {
        resolve(response);
      }
      reject(new Error("Request is failed"));
    });
  });
}

// FulfilledまたはRejectedの結果出力
getData().then(function (data) {
  console.log(data); // response値出力
}).catch(function (err) {
  console.error(err); // Error出力
});

上記のコードは、サーバー上で正常応答を受けてきたらresolve()メソッドを呼び出して、

応答がない場合reject()メソッドを呼び出す例です。

呼び出されたメソッドに基づいてthen()catch()に分岐して、データやエラーを出力する。

 

 

複数のプロミス接続する(Promise Chaining)

プロミスのもう一つの特徴は、複数のプロミスを接続して使用することができているという点である。

前の例ではthen()メソッドを呼び出しした後、新しいプロミスオブジェクトが返される。

したがって、以下のようにコーディングが可能である。

function getData() {
  return new Promise({
    // ...
  });
}

// then()で、複数のプロミスを接続した形式
getData()
  .then(function (data) {
    // ...
  })
  .then(function () {
    // ...
  })
  .then(function () {
    // ...
  });

その後、上記の形式を参考にして、実際に返し見ることができる例を見てみよう。

非同期処理の例で最も一般的に使用されているsetTimeout() APIを使用した。

new Promise(function(resolve, reject){
  setTimeout(function() {
    resolve(1);
  }, 2000);
})
.then(function(result) {
  console.log(result); // 1
  return result + 10;
})
.then(function(result) {
  console.log(result); // 11
  return result + 20;
})
.then(function(result) {
  console.log(result); // 31
});

 上記のコードは、プロミスオブジェクトを一つ生成しsetTimeout()を利用して2秒後にresolve()を呼び出す例です。

resolve()が呼び出されると、プロミスが待機状態で

移行状態に進むため、最初の.then()のロジックに移る。

最初の.then()は実施された結果の値1を受けて、10を加えた後、その次の.then()に渡してくれる。

第二.then()も同様に直前プロミスの結果値11を受けて、20を加えて、以下の.then()に渡してくれる。

最後.then()で最終結果値31を出力する。

 

実務であるようなプロミス接続事例

実際のWebサービスであるような、ユーザーのログイン認証ロジックにプロミスを複数接続してみよう。

getData(userInfo)
  .then(parseValue)
  .then(auth)
  .then(diaplay);

上記のコードは、ページに入力されたユーザ情報を取得し、解析、認証などの作業を経るコードを示した。

ここで、userInfoは、ユーザー情報が含まれたオブジェクトを意味し、

parseValueauthdisplayはそれぞれプロミスを関数と仮定した。 

 

var userInfo = {
  id: 'test@abc.com',
  pw: '****'
};

function parseValue() {
  return new Promise({
    // ...
  });
}
function auth() {
  return new Promise({
    // ...
  });
}
function display() {
  return new Promise({
    // ...
  });
}

このように、複数のプロミスを.then()に接続して処理することができる。

 

プロミスのエラー処理方法

前述のプロミスの例では、コードが常に正常に動作すると仮定して実装した例である。

実際のサービスを実装してみると、ネットワーク接続、状態コードの問題などが原因でエラーが発生しすることができる。

したがって、プロミスのエラー処理方法についても知っておくべきである。

 

エラー処理方法には、次のように2つの方法がある。

 

1. then()の2番目の引数でエラーを処理する方法

getData().then(
  handleSuccess,
  handleError
);

 

2.catch()を利用する方法

getData().then().catch();

 

上記2つの方法の両方プロミスのreject()メソッドが呼び出されて失敗した状態になった場合に実行される。

簡単に言えばプロミスのロジックが正常に戻らない場合に呼び出されるのだ。

function getData() {
  return new Promise(function (resolve, reject) {
    reject('failed');
  });
}

// 1. then()でエラーを処理するコード
getData().then(function () {
  // ...
}, function (err) {
  console.log(err);
});

// 2. catch()でエラーを処理するコード
getData().then().catch(function (err) {
  console.log(err);
});

 

プロミスエラー処理はなるべくcatch()で

前プロミスエラー処理方法を2つ調べた。

一人一人のコーディングスタイルに応じthen()の二番目の引数を処理することも、catch()で処理することもあるだろうが

なるべくcatch()でエラーを処理するのがより効率的である。

// then()の2番目の引数には、検出されないエラー
function getData() {
  return new Promise(function (resolve, reject) {
    resolve('hi');
  });
}

getData().then(function (result) {
  console.log(result);
  throw new Error("Error in then()"); // Uncaught (in promise) Error: Error in then()
}, function (err) {
  console.log('then error : ', err);
});

getData()関数のプロミスでresolve()メソッドを呼び出して、通常のロジックを処理したが、

then()の最初のコールバック関数の内部でエラーが出る場合は、エラーを適切に保持するられない。

したがって、コードを実行すると、以下のようなエラーが出る。

 

「エラーを雑誌でした(Uncaught Error)」のログ

しかし、同じエラーをcatch()で処理すると、他の結果が出てくる。

// catch()でエラーを検出するためのコード
function getData() {
  return new Promise(function (resolve, reject) {
    resolve('hi');
  });
}

getData().then(function (result) {
  console.log(result); // hi
  throw new Error("Error in then()");
}).catch(function (err) {
  console.log('then error : ', err); // then error :  Error: Error in then()
});

上記のコードと処理結果は、以下の通りである。

発生したエラーを正常にコンソールに出力した様子

 

したがって、より多くの例外処理状況のためにプロミスの終わりになるべくcatch()を付けるください。

 

Comments