Promise對象

一、案例

Promise用於對異步操做的進行數據處理,爲異步操做的回調函數提供接口,讓其在可同步執行,而不用再將回調函數進行層層嵌套。
例如,咱們如下面的例子爲例:javascript

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Index</title>
</head>
<body>
    <div id="app"></div>
    <template id="template">
        <p></p>
    </template>
</body>
<script type="text/javascript">
    var app = document.querySelector('#app');
    var p = document.getElementById('template').content.querySelector('p');
    var p1 = p.cloneNode(true);
    var p2 = p.cloneNode(true);
    var p3 = p.cloneNode(true);

    var i = 0, html;
    window.setTimeout(() => {
        p1.innerHTML = '<p>aaaaaaaa</p>';
        app.appendChild(p1);
    }, 100);
    window.setTimeout(() => {
        p2.innerHTML = '<p>bbbbbbbb</p>';
        app.appendChild(p2);
    }, 200);
    window.setTimeout(() => {
        p3.innerHTML = '<p>cccccccc</p>';
        app.appendChild(p3);
    }, 50);
</script>
</html>

對於異步函數,若是不進行回調函數嵌套,咱們就沒法保證其執行順序。可是有了Promise對象以後,咱們能夠進行鏈式書寫,從而保證回調執行的順序。php

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Index</title>
</head>
<body>
    <div id="app"></div>
    <template id="template">
        <p></p>
    </template>
</body>
<script type="text/javascript">
    var app = document.querySelector('#app');
    var p = document.getElementById('template').content.querySelector('p');
    var p1 = p.cloneNode(true);
    var p2 = p.cloneNode(true);
    var p3 = p.cloneNode(true);

    var i = 0, html;
    var promise1 = new Promise((resolve, reject) => {
        window.setTimeout(() => {
            p1.innerHTML = '<p>aaaaaaaa</p>';
            resolve(p1, promise2);
        }, 100);
    });
    var promise2 = new Promise((resolve, reject) => {
        window.setTimeout(() => {
            p2.innerHTML = '<p>bbbbbbbb</p>';
            resolve(p2, promise3);
        }, 200);
    });
    var promise3 = new Promise((resolve, reject) => {
        window.setTimeout(() => {
            p3.innerHTML = '<p>cccccccc</p>';
            resolve(p3, null);
        }, 50);
    });
    promise1.then((node) => {
        app.appendChild(node);
        return promise2;
    }).then((node) => {
        app.appendChild(node);
        return promise3;
    }).then((node) => {
        app.appendChild(node);
    });
</script>
</html>

二、Promise的基本語法

Promise對象是一個代理對象(代理一個值),被代理的值在Promise對象建立時多是未知的。它容許你爲異步操做的成功和失敗分別綁定相應的處理方法(handlers)。 這讓異步方法能夠像同步方法那樣返回值,但並非當即返回最終執行結果,而是一個能表明將來出現的結果的promise對象。html

根據以上描述,咱們能夠知道,Promise對象能夠代理一個異步處理的結果。因此Promise有fulfilled(已成功)狀態和rejected(已失敗)兩個狀態,對應Promise構造函數的兩個回調函數:resolverejectjava

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

在執行回調函數以前,Promise的狀態爲pedding,當執行resolve後狀態變爲fulfilled,執行reject以後裝態變爲rejectednode

原型方法:jquery

//添加一個拒絕(rejection) 回調到當前 promise, 返回一個新的promise。
Promise.prototype.catch(onRejected)

//添加一個拒絕(rejection) 回調到當前 promise, 返回一個新的promise。當這個回調函數被調用,新 promise 將以它的返回值來resolve,不然若是當前promise 進入fulfilled狀態,則以當前promise的完成結果做爲新promise的完成結果.
Promise.prototype.then(onFulfilled, onRejected)

//不管當前promise的狀態是完成(fulfilled)仍是失敗(rejected),都會執行
Promise.prototype.finally(onFinally)

三、Jquery中的deferred對象

Jquery中的deferred對象是原生Promise接口的實現。用法大同小異。ajax

ajax中咱們能夠直接使用,由於1.5版本以後,ajax返回的值就是一個defeered對象。promise

舊的寫法:app

  $.ajax({
    url: "test.html",
    success: function(){
      alert("成功了!");
    },
    error:function(){
      alert("出錯啦!");
    }
  });

新的寫法:異步

//更簡潔的鏈式寫法
$.ajax("test.html")
  .done(function(){ alert("成功了!"); })
  .fail(function(){ alert("出錯啦!"); });

並且deferred對象不單單是在ajax中使用,也能夠在任何回調中進行使用。

好比:

var $dfd = $.Deferred();//建立一個deferred實例對象
var success = 0;//模擬成功失敗狀態
window.setTimeout(() => {
    if(success === 0){
        $dfd.resolve();
    }else{
         $dfd.reject();
    }
}, 100);
//兩種寫法:
$dfd.done(function(){
    alert('成功');
}).fail(function(){
    alert('失敗');
});
//------另外一種寫法
$dfd.then(function(){
     alert('成功');
},function(){
     alert('失敗');
});

一樣的道理,使用deferred對象重寫書寫上面的案例:

<head>
    <meta charset="utf-8">
    <title>Index</title>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>
<body>
    <div id="app"></div>
    <template id="template">
        <p></p>
    </template>
</body>
<script type="text/javascript">
    var app = $('#app');
    var p = $('#template')[0].content.querySelector('p');
    var p1 = p.cloneNode(true);
    var p2 = p.cloneNode(true);
    var p3 = p.cloneNode(true);

    var i = 0, html;
    var dfd1 = $.Deferred(),
        dfd2 = $.Deferred(),
        dfd3 = $.Deferred();
    window.setTimeout(() => {
        p1.innerHTML = '<p>aaaaaaaa</p>';
        dfd1.resolve();
    }, 100);
    window.setTimeout(() => {
        p2.innerHTML = '<p>bbbbbbbb</p>';
        dfd2.resolve();
    }, 200);
    window.setTimeout(() => {
        p3.innerHTML = '<p>cccccccc</p>';
        dfd3.resolve();
    }, 50);

    dfd1.done(function(){
        app.append(p1);
        return dfd2;
    }).done(function(){
        app.append(p2);
        return dfd3;
    }).done(function(){
        app.append(p3);
    });
</script>
</html>

另外:jquery還提供了一個同時監聽多個回調的方法。$.when(),返回值爲defferred對象。

$.when()接受多個deferred對象做爲參數,當它們所有運行成功後,才調用resolved狀態的回調函數,但只要其中有一個失敗,就調用rejected狀態的回調函數。它至關於將多個非同步操做,合併成一個。實質上,when方法爲多個deferred對象,返回一個單一的promise對象。

$.when(
    $.ajax( "/main.php" ),
    $.ajax( "/modules.php" ),
    $.ajax( "/lists.php" )
).then(successFunc, failureFunc);
參考來源:

https://wangdoc.com/javascript/async/promise.html
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises
http://javascript.ruanyifeng.com/jquery/deferred.html#toc0

相關文章
相關標籤/搜索