// sync, await
function sleep(time)
{
    return new Promise(function (resolve, reject)
    {
        setTimeout( function () { resolve('ok'); }, time);
    });
}
 
async function start()
{
    try 
    {
        var result = await sleep(3000);
        var r = await timeout();
        document.getElementById("debug").innerHTML += JSON.stringify(result, undefined, 2);
        document.getElementById("debug").innerHTML += "<br>";
 
        document.getElementById("debug").innerHTML += JSON.stringify(r, undefined, 2);
        document.getElementById("debug").innerHTML += "<br>";
    }
    catch (err) // reject data will be in err
    {
        document.getElementById("debug").innerHTML += JSON.stringify(err, undefined, 2);
        document.getElementById("debug").innerHTML += "<br>";
    }
}
 
start();
 
// promise then...
// http://www.cnblogs.com/lvdabao/p/es6-promise-1.html
function runAsync()
{
    var p = new Promise(function(resolve, reject)
    {
        setTimeout(function()
        {
            document.getElementById("debug").innerHTML += "do something...";
            document.getElementById("debug").innerHTML += "<br>";
            resolve('ok');
        }, 2000);
    });
    return p;
}
 
runAsync();
 
// promise resolve...
function runAsync1()
{
    var p = new Promise(function(resolve, reject)
    {
        setTimeout(function()
        {
            document.getElementById("debug").innerHTML += "do something...1";
            document.getElementById("debug").innerHTML += "<br>";
            resolve('runAsync1');
        }, 1000);
    });
    return p;
}
function runAsync2(){
    var p = new Promise(function(resolve, reject)
    {
        setTimeout(function()
        {
            document.getElementById("debug").innerHTML += "do something...2";
            document.getElementById("debug").innerHTML += "<br>";
            resolve('runAsync2');
        }, 2000);
    });
    return p;
}
function runAsync3()
{
    var p = new Promise(function(resolve, reject)
    {
        setTimeout(function()
        {
            document.getElementById("debug").innerHTML += "do something...3";
            document.getElementById("debug").innerHTML += "<br>";
            resolve('runAsync3');
        }, 2000);
    });
    return p;
}
 
runAsync1()
.then(function(data1)
{
    document.getElementById("debug").innerHTML += data1;
    document.getElementById("debug").innerHTML += "<br>";
    return runAsync2(); // this return will be the next then's data2
})
.then(function(data2){
    document.getElementById("debug").innerHTML += data2;
    document.getElementById("debug").innerHTML += "<br>";
    return runAsync3();
})
.then(function(data3)
{
    document.getElementById("debug").innerHTML += data3;
    document.getElementById("debug").innerHTML += "<br>";
});
 
// promise reject...
function getNumber()
{
    var p = new Promise(function(resolve, reject){
        setTimeout(function()
        {
            var num = Math.ceil(Math.random()*10);
            if(num<=5)
            {
                resolve(num);
            }
            else{
                reject('number is too big');
            }
        }, 2000);
    });
    return p;            
}
 
getNumber()
.then(
    function(data) // resolved callback
    {
        document.getElementById("debug").innerHTML += "resolved->";
        document.getElementById("debug").innerHTML += data;
        document.getElementById("debug").innerHTML += "<br>";
    }, 
    function(reason, data) // rejected callback
    {
        document.getElementById("debug").innerHTML += "rejected->";
        document.getElementById("debug").innerHTML += reason;
        document.getElementById("debug").innerHTML += "<br>";
    }
);
 
// promise catch...
getNumber()
.then(function(data) // resolved callback
{
    document.getElementById("debug").innerHTML += "resolved->";
    document.getElementById("debug").innerHTML += data;
    document.getElementById("debug").innerHTML += "<br>";
    document.getElementById("debug").innerHTML += unknow;
})
.catch(function(reason) // rejected callback, and if resolved callback failed, it will go here
{
    document.getElementById("debug").innerHTML += "rejected->";
    document.getElementById("debug").innerHTML += reason;
    document.getElementById("debug").innerHTML += "<br>";
});
 
// promise all: the slowest callback is the calling standard, so all data will be in "results"
Promise
.all([runAsync1(), runAsync2(), runAsync3()]) // 
.then(function(results)
{
    document.getElementById("debug").innerHTML += results;
    document.getElementById("debug").innerHTML += "<br>";
});
 
// promise race: the fastest callback is the calling standard, so the fastest callback's return data will be in "results"
Promise
.race([runAsync1(), runAsync2(), runAsync3()])
.then(function(results)
{
    document.getElementById("debug").innerHTML += results;
    document.getElementById("debug").innerHTML += "<br>";
});
 
// promise race: the example for timeout
// promise race also can be use for fault-tolerant design
function requestImg()
{
    var p = new Promise(function(resolve, reject)
    {
        var img = new Image();
        img.onload = function()
        {
            resolve(img);
        }
        img.src = 'xxxxxx';
    });
    return p;
}
 
function timeout()
{
    var p = new Promise(function(resolve, reject)
    {
        setTimeout(function()
        {
            reject('image request timeout');
        }, 5000);
    });
    return p;
}
 
Promise
.race([requestImg(), timeout()])
.then(function(results)
{
    document.getElementById("debug").innerHTML += results;
    document.getElementById("debug").innerHTML += "<br>";
})
.catch(function(reason)
{
    document.getElementById("debug").innerHTML += reason;
    document.getElementById("debug").innerHTML += "<br>";
});