首頁  >  文章  >  web前端  >  ES6新功能:JavaScript中內建的延遲物件Promise 程式碼詳細介紹

ES6新功能:JavaScript中內建的延遲物件Promise 程式碼詳細介紹

黄舟
黄舟原創
2017-03-07 14:26:431450瀏覽

Promise的基本使用:

利用Promise是解決JS非同步執行時候回呼函數巢狀回呼函數的問題, 更簡潔地控制函數執行流程;

透過new實例化Promise, 建構函數需要兩個參數, 第一個參數為函數執行成功以後執行的函數resolve,第二個函數為函數執行失敗以後執行的函數reject:

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

透過Promise,我們把回呼函數用線性的方式寫出來,而不是一層套一層, 這個函數有四層回呼;

fn("args", function(a) {
    fn1("foo", function(b) {
        fn2("bar", function(c) {
            fn3("baz", function(d) {
                alert("回调成功,获知的内容为:"+a+b+c+d)
            })
        })
    })
})

以上的Demo只有包含成功的回呼, 如果失敗的回呼也算的話, 也就更麻煩了;

如果使用Promise的方式,我們可以改裝成線性的程式碼,更符合閱讀的習慣,只要在then函數下寫邏輯即可;

new Promise(function(resolve , reject) {
    resolve(1);
}).then(function(val) {
    console.log(val);
    return new Promise(function(resolve , reject) {
        resolve(2);
    });
}).then(function(val) {
    console.log(val);
    return new Promise(function(resolve , reject) {
        resolve(3);
    });
}).then(function(val) {
    console.log(val);
    return new Promise(function(resolve , reject) {
        resolve(4);
    });
}).then(function(val) {
    console.log(val);
});

這是一個ajax異步獲取資料的例子, 我們使用了回呼函數;

<html>
<head>
    <meta charset="utf-8">
</head>
<body>
<script>
    var callback = function(res) {
        console.log(res);
    };
    var ajax = function(url, callback) {
        var r = new XMLHttpRequest();
        r.open("GET", url, true);
        r.onreadystatechange = function () {
            if (r.readyState != 4 || r.status != 200) return;
            var data = JSON.parse(r.responseText);
            callback(data);
        };
        r.send();
    };
    //执行请求:
    ajax("http://www.filltext.com?rows=10&f={firstName}", callback);
    //再做别的事情;
</script>
</body>
</html>

因為ES6內建了Promise, 我們可以把以上的callback改寫成promise的方式, 首先ajax函數回傳一個Promise物件;

<html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <script>
        var callback = function(res) {
            console.log(res);
        };
        var ajax = function(url) {
            return new Promise(function(resolve, reject) {
                var r = new XMLHttpRequest();
                r.open("GET", url, true);
                r.onreadystatechange = function () {
                    if (r.readyState != 4 || r.status != 200) return;
                    var data = JSON.parse(r.responseText);
                    resolve(data);
                };
                r.send();
            })
        };
        //执行请求:
        ajax("http://www.filltext.com?rows=10&f={firstName}").then(function(data) {
            callback(data);
        });
        //再做别的事情;
    </script>
</body>
</html>

Promise實例的三種狀態:

每一個實例化的Promise都有三個狀態;pending(等待)  rejected(拒絕)  resolved(解決) ,預設的狀態為pending,如果執行了resolve(), 那麼這個promise的狀態會變為resolve,如果執行了reject(), 那麼這個promise的狀態就會變成rejected, 而且這些狀態是不可撤銷的,一經更改,不會再變了;

then方法:

promise有一個then方法,then方法接收兩個參數, 第一個為函數的成功回調, 第二個為函數的失敗回呼:

var promise = new Promise(function(resolve , reject) {
    resolve(); //执行成功回调;
});
console.log(0);
promise.then(function(val) {
    console.log(1); 
}, function() {
    console.log("失败");
});
console.log("2");
var promise = new Promise(function(resolve , reject) {
    reject();
});
console.log(0);
promise.then(function(val) {
    console.log(1);
}, function() {
    console.log("失败");
});
console.log("2");

then方法每一次都是傳回不同的Promise實例,then的第一個參數是成功回調, 這個成功回呼的參數為: 上一個Promise實例執行resolve方法的參數;

一般來說, then方法會傳回目前的 promise , 如果在then方法裡面return 一個新的Promise實例,那麼此時的then返回的就是新的Promise實例, 利用這個特性,就可以實現多層回調;

new Promise(function(resolve , reject) {
    resolve(1);
}).then(function(val) {
    console.log(val);
    return new Promise(function(resolve , reject) {
        resolve(2);
    });
}).then(function(val) {
    console.log(val);
    return new Promise(function(resolve , reject) {
        resolve(3);
    });
}).then(function(val) {
    console.log(val);
    return new Promise(function(resolve , reject) {
        resolve(4);
    });
}).then(function(val) {
    console.log(val);
});

不管程式碼是異步還是同步的, 都可以用Promise的then方法, 同步的程式碼直接寫在then方法第一個參數, 把需要參數透過resolve傳給下一個then方法,

#如果是異步的程式碼,就直接return一個Promise實例:

new Promise(function(resolve , reject) {
    resolve(1);
}).then(function(val) {
    console.log(val);
    return 2;
}).then(function(val) {
    console.log(val);
    return 3;
}).then(function(val) {
    console.log(val);
    return new Promise(function(resolve,reject) {
        //异步操作些这里
        resolve(4);
    });
}).then(function(val) {
    console.log(val);
    return 5;
}).then(function(val) {
    console.log(val);
});

catch方法:

catch方法和失敗回呼時一樣的, 如果上一個非同步函數 拋出了錯誤了,錯誤會被捕獲, 並執行 catch方法或失敗回呼;

var promise = new Promise(function(resolve , reject) {
    resolve(); //执行成功回调;
});
console.log(0);
promise.then(function(val) {
    console.log("成功");
    throw new Error("heheda");
}).catch(function(e) {
    console.log(e);
}).then(function() {
    console.log("继续执行");
});

Promise中的錯誤是會一層層傳遞的, 如果錯誤沒有沒有被捕獲, 會一直傳遞給下一個promise對象, 直到被捕獲為止, 然後繼續往下執行:

new Promise(function(resolve , reject) {
    resolve(1);
}).then(function(val) {
        console.log(val);
        return new Promise(function(resolve , reject) {
            throw new Error("err");
        });
    }).then(function(val) {
        console.log(val);
        return new Promise(function(resolve , reject) {
            resolve(3);
        });
    }).then(function(val) {
        console.log(val);
        return new Promise(function(resolve , reject) {
            resolve(4);
        });
    }).then(function(val) {
        console.log(val);
    }).catch(function(err) {
        console.log(err);
    }).then(function() {
        console.log("继续执行")
    })

建構子Promise的四個方法:

建構子Promise有四個方法, Promise .all, Promise.race, Promise.reject, Promise.resolve:

Promise.all(iterable)
返回一個promise對象,當iterable參數裡所有的promise都被解決後,該promise也會被解決

要注意all方法是Promise函數的方法,不是實例的方法,參數是數組, 數組裡面全是Promise的實例 :

var p0 = new Promise(function(resolve) {
    setTimeout(function() {
        resolve(0)
    },1000);
})
var p1 = new Promise(function(resolve) {
    setTimeout(function() {
        resolve(1)
    },2000);
})
var p2 = new Promise(function(resolve) {
    setTimeout(function() {
        resolve(2)
    },3000);
})
Promise.all([p0,p1,p2]).then(function(arr) {
    console.log(arr)
})

Promise.race(iterable)

當iterable參數裡的任一個子promise被成功或失敗後,父promise馬上也會以子promise的成功傳回值或失敗詳情作為參數呼叫父promise綁定的對應句柄,並傳回該promise物件。

Promise.reject(reason)

#呼叫Promise的rejected句柄,並傳回這個Promise物件。

Promise.resolve(value)

#用成功值value解決一個Promise物件。如果該value為可繼續的(thenable,即帶有then方法),則傳回的Promise物件會「跟隨」這個value,採用這個value的最終狀態;否則的話傳回值會用這個value滿足(fullfil)傳回的Promise對象。

官方的範例:

<html>
<head>
    <meta charset="utf-8">
</head>
<body>
<p id="log"></p>
<script>
    &#39;use strict&#39;;
    var promiseCount = 0;
    function testPromise() {
        var thisPromiseCount = ++promiseCount;

        var log = document.getElementById(&#39;log&#39;);
        log.insertAdjacentHTML(&#39;beforeend&#39;, thisPromiseCount + &#39;) 开始(同步代码开始)<br/>&#39;);

        // 我们创建一个新的promise: 然后用&#39;result&#39;字符串解决这个promise (3秒后)
        var p1 = new Promise(function (resolve, reject) {
            // 解决函数带着解决(resolve)或拒绝(reject)promise的能力被执行
            log.insertAdjacentHTML(&#39;beforeend&#39;, thisPromiseCount + &#39;) Promise开始(异步代码开始)<br/>&#39;);

            // 这只是个创建异步解决的示例
            window.setTimeout(function () {
                // 我们满足(fullfil)了这个promise!
                resolve(thisPromiseCount)
            }, Math.random() * 2000 + 1000);
        });

        // 定义当promise被满足时应做什么
        p1.then(function (val) {
            // 输出一段信息和一个值
            log.insertAdjacentHTML(&#39;beforeend&#39;, val + &#39;) Promise被满足了(异步代码结束)<br/>&#39;);
        });

        log.insertAdjacentHTML(&#39;beforeend&#39;, thisPromiseCount + &#39;) 建立了Promise(同步代码结束)<br/><br/>&#39;);
    }
    testPromise();
</script>
</body>
</html>

既然有了Promise , 我們就可以把封裝XMLHttpRequest封裝成GET方法,方便使用:

function get(url) {
  // Return a new promise.
  return new Promise(function(resolve, reject) {
    // Do the usual XHR stuff
    var req = new XMLHttpRequest();
    req.open(&#39;GET&#39;, url);

    req.onload = function() {
      // This is called even on 404 etc
      // so check the status
      if (req.status == 200) {
        // Resolve the promise with the response text
        resolve(req.response);
      }
      else {
        // Otherwise reject with the status text
        // which will hopefully be a meaningful error
        reject(Error(req.statusText));
      }
    };

    // Handle network errors
    req.onerror = function() {
      reject(Error("Network Error"));
    };

    // Make the request
    req.send();
  });
}

然後使用:

get(&#39;story.json&#39;).then(function(response) {
  console.log("Success!", response);
}, function(error) {
  console.error("Failed!", error);
});

假資料的位址可以自己設置, 可以透過控制台請求, 注意跨域的問題;

封裝XMLHttpRequest成Promise非同步載入圖片的案例:http: //www.php.cn/

其他:

以上只是Promise的一些基礎知識, 還有一些其他的知識點, 因為能力有限不一一介紹了(Promise.resolve的不同參數, 與Generator一起使用, Promise的附加方法, 等等等等);

把Promise的運行流程畫出來, 對Promise的理解會好一點, Promise還是比較繞的

瀏覽器支援情況:

#

Chrome 32, Opera 1,Firefox 29, Safari 8 ,Microsoft Edge, 這些瀏覽器以上都預設支援;

 以上就是ES6新功能:JavaScript中內建的延遲物件Promise 程式碼詳細介紹的內容,更多相關內容請關注PHP中文網(www.php.cn)!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn