Promise는 비동기 연산이 종료된 이후 결과값 또는 실패 이유를 반환합니다. 비동기 연산을 동기 연산처럼 사용 가능합니다. 비동기 연산이기 때문에 바로 값을 반환하지 않고, 미리 프로미스를 반환해서 연산이 완료된 시점에 결과를 반환합니다.
Promise에는 3가지 상태가 있습니다.

var myPromise = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve("success!");
    },1000);
});
myPromise
.then((message)=>{
    console.log("First Promise "+message);
});
var arr = [1,2,3,4,5,6,7,8,9,10];
for(var i of arr){
    console.log(i);
}
//1,2,3,4,5,6,7,8,9,10,First Promise success!
위의 예제에서는 1초 뒤에 success! 메세지를 반환하기 때문에 반복문이 먼저 실행되고 .then이 실행되는 것을 볼수 있습니다.
이때 for문을 먼저 실행시키려면 ES7부터 추가된 async/await 문법을 사용하면 됩니다.
async/await 문법을 사용하면 비동기 코드를 동기코드 처럼 사용할수 있습니다.
var myPromise = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve("success!");
    },1000);
});
const printMessage = async() => {
    const message = await myPromise;
    console.log("First Promise "+message);
    
    myPromise
    .then((m)=>{
        console.log("second Promise "+m)    
    })
    
    var arr = [1,2,3,4,5,6,7,8,9,10];
    for(var i of arr){
        console.log(i);
    }
}
printMessage();
//First Promise success!,1,2,3,4,5,6,7,8,9,10,second Promise success!
이와 같이 async 함수에 await을 붙이면 await 뒤의 Promise가 반환되기 전까지 다음 코드로 진행되지 않는 것을 확인할수 있습니다.
.then 과 async/await 실행 시간을 랜덤으로 주고 실행해보면 더욱 확실하게 비교해 볼수 있습니다.
var arr = [1,2,3,4,5,6,7,8,9,10];
var myPromise = (num) => new Promise((resolve,reject)=>{
    const time = Math.random();
    setTimeout(()=>{
        resolve(num);
    },Number(time*100));
});
const syncMessage = async() => {
    for(var num of arr){
        const message = await myPromise(num);
        console.log(message);
    }
}
const asyncMessage = () => {
    for(var num of arr){
        myPromise(num)
        .then((message)=>{
            console.log("async",message);
        });
    }
}
syncMessage();
asyncMessage();
참고자료