Promise 詳解


  在JavaScript的世界中,所有代碼都是單線程執行的。由於這個“缺陷”,導致JavaScript的所有網絡操作,瀏覽器事件,都必須是異步執行。原來異步執行都用回調函數實現,現在可以使用Promise來實現異步。

  有時在業務中需要執行一層套一層套一層...的異步回調來獲取數據,也就是地獄回調,

$.ajax({
    url:"",
    success: function(res1){
        $.ajax({
            url:"",
            data: {key:res1},
            success: function(res2){
                $.ajax({
                    url:"",
                    data: {key:res2},
                    success:function(res3){
                        
                    }
                })
            }
        })
    }
})

  現在可以使用Promise來解決地獄回調的復雜嵌套問題。

var p = new Promise((res,rej)=>{
    let data = 10;
   // 使用setTimeout模擬異步,data是異步請求回的數據,setTimeout其實有三個值,第三個值是第一個值函數的參數
   setTimeout(res,1000,data+data)
});
function a(data){
    return new Promise((res,rej)=>{
        setTimeout(res,1000,data+data)
    })
};
function b(data){
    return new Promise((res,rej)=>{
        setTimeout(res,1000,data+data)
    })
};
p.then(function(res){
    console.log(res); // 20
    return a(res)
}).then(function(res){
    console.log(res); //40
    return b(res)
}).then(function(res){
    console.log(res); //80
});        

描述

  Promise 對象是一個代理對象(代理一個值),被代理的值在Promise對象創建時可能是未知的。它允許你為異步操作的成功和失敗分別綁定相應的處理方法(handlers)。 這讓異步方法可以像同步方法那樣返回值,但並不是立即返回最終執行結果,而是一個能代表未來出現的結果的promise對象。

一個 Promise有以下幾種狀態:

pending: 初始狀態,既不是成功,也不是失敗狀態。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失敗

  pending 狀態的 Promise 對象可能會變為fulfilled 狀態並傳遞一個值給相應的狀態處理方法,也可能變為失敗狀態(rejected)並傳遞失敗信息。當其中任一種情況出現時,Promise 對象的 then 方法綁定的處理方法(handlers )就會被調用(then方法包含兩個參數:onfulfilled 和 onrejected,它們都是 Function 類型。當Promise狀態為fulfilled時,調用 then 的 onfulfilled 方法,當Promise狀態為rejected時,調用 then 的 onrejected 方法, 所以在異步操作的完成和綁定處理方法之間不存在競爭)。

因為 Promise.prototype.then 和  Promise.prototype.catch 方法返回promise 對象, 所以它們可以被鏈式調用。

  

語法

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

 

方法 

  1、Promise.prototype.catch(onRejected)添加一個拒絕(rejection) 回調到當前 promise, 返回一個新的promise。當這個回調函數被調用,新 promise 將以它的返回值來resolve,否則如果當前promise 進入fulfilled狀態,則以當前promise的完成結果作為新promise的完成結果

  2、.Promise.prototype.then(onFulfilled, onRejected)添加解決(fulfillment)和拒絕(rejection)回調到當前 promise, 返回一個新的 promise, 將以回調的返回值來resolve.

  3、Promise.prototype.finally(onFinally)添加一個事件處理回調於當前promise對象,並且在原promise對象解析完畢后,返回一個新的promise對象。回調會在當前promise運行完畢后被調用,無論當前promise的狀態是完成(fulfilled)還是失敗(rejected)

  備注:由於 then() 和 catch()方法都會返回 promise,它們可以被鏈式調用,由此才可以實現then的鏈式調用來實現多重回調 

實例

  1、一般promise

var p = new Promise(function(resolve,reject){
  // 當異步代碼執行成功時,我們才會調用resolve(...),當異步代碼失敗時調用reject(...);
  // 使用setTimeout(...)來模擬異步代碼
if(Math.random()>0.5){ setTimeout(resolve,1000,res) }else{ setTimeout(reject,1000,rej) } }); p.then(function(res){ console.log(res); }).catch(function(rej){ console.log(rej); });

  2、當promise的then中存在兩個函數,且走reject回調失敗時,catch中的錯誤回調無效

var a = new Promise((resolve,reject)=>{
    if(false){
        resolve('這是大於0.5')
    } else {
        reject("這是小於等於0.5");
    }
});
a.then(
    function(res){console.log("then");console.log(res)}
).catch(
    function(res){console.log("catch");console.log(res)} // catch 這是小於等於0.5
);
a.then(
    function(res){console.log("then");console.log(res)},
    function(rej){console.log("then");console.log(rej)} // then 這是小於等於0.5
).catch(
    function(rej){console.log("catch");console.log(rej)}
);

  3、地獄回調:不同人寫的處理地獄回調方式中return的數量不一樣,造成困惑,仔細觀察還是有不同

function multiply(input) {
    return new Promise(function (resolve, reject) {
        console.log('calculating ' + input + ' x ' + input + '...');
        setTimeout(resolve, 500, input * input);
    });
};
function add(input) {
    return new Promise(function (resolve, reject) {
        console.log('calculating ' + input + ' + ' + input + '...');
        setTimeout(resolve, 500, input + input);
    });
};
var p = new Promise(function (resolve, reject) {
    console.log('start new Promise...');
    resolve(123);
});
// 這是把自定義函數直接當做then中的匿名函數,所有只需要在自定義的函數中返回promise就可以實現then的鏈式調用 p.then(multiply) .then(add) .then(multiply) .then(add) .then(function (result) { console.log(
'Got value: ' + result); });
// 嚴格按照then中的匿名函數寫法,先是自定義函數內部return出promise實例,再在匿名函數中return出promise實例,這樣就可以實現then的鏈式調用
p.then(
  function(res){
    return multiply(res)
  }
).then(
  function(res){
    return add(res)
  }
)
.then(
  function(res){
    return multiply(res)
  }
).then(
  function(res){
    return add(res)
  }
).then(
  function(res){
    console.log('Got value'+res)
  }
)
 
        

Promise.all(iterable) :iterable是一個可迭代對象,如 Array 或 String

  Promise.all(iterable) 方法返回一個 Promise 實例,此實例在 iterable 參數內所有的 promise 都“完成(resolved)”或參數中不包含 promise 時回調完成(resolve);如果參數中  promise 有一個失敗(rejected),此實例回調失敗(reject),失敗的原因是第一個失敗 promise 的結果。

const p1 = Promise.resolve(3);
const p2 = 42;
const p3 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, 'foo');
});
const p4 = new Promise(function(resolve,reject){
  setTimeout(reject,1000,'fail')
}) Promise.all([p1, p2, p3]).then(function(values) { console.log(values); });
// expected output: Array [3, 42, "foo"]

Promise.all([p1,p2,p3,p4]).then(function(res){
  console.log(res)
}).catch(function(rej){
  console.log("rej:"+rej)
})
//
expected output: String rej:fail

 

Promise.race(iterable) :iterable是一個可迭代對象,如 Array 或 String

  顧名思義,Promse.race就是賽跑的意思,意思就是說,Promise.race([p1, p2, p3])里面哪個結果獲得的快,就返回那個結果,不管結果本身是成功狀態還是失敗狀態,如果出現同時,那么久看Promise的哪個實例的位置,實例最早,就返回那個結果,無論成功狀態還是失敗狀態。不是race中數組的位置,是在js中promise實例位置。

  

let p1 = new Promise(function(resolve,reject){
		setTimeout(resolve,1000,"時間1000,p1的resolve成功")
	});
	let p2 = new Promise(function(resolve,reject){
		setTimeout(resolve,500,'時間:500,p2的resolve成功')
	})
	let p3 = new Promise(function(resolve,reject){
		setTimeout(reject,1000,"時間1000,p3的reject失敗")
	});
	let p4 = new Promise(function(resolve,reject){
		setTimeout(reject,500,'時間:500,p4的reject失敗')
	});
	let p5 = new Promise(function(resolve,reject){
		setTimeout(resolve,1000,'時間:1100,p5的resolve成功')
	});
	Promise.race([p1,p2]).then(function(res){
		console.log(res);  // 時間500,p2的resolve成功
	}).catch(function(rej){
		console.log(rej);
	});
	Promise.race([p1,p3]).then(function(res){
		console.log(res); // 時間1000,p1的resolve成功
	}).catch(function(rej){
		console.log(rej);
	});
	Promise.race([p3,p1]).then(function(res){
		console.log(res); // 時間1000,p1的resolve成功
	}).catch(function(rej){
		console.log(rej);
	});
	Promise.race([p1,p5]).then(function(res){
		console.log(res); // 時間1000,p1的resolve成功
	}).catch(function(rej){
		console.log(rej);
	});
	Promise.race([p5,p1]).then(function(res){
		console.log(res); // 時間1000,p1的resolve成功
	}).catch(function(rej){
		console.log(rej);
	});
	Promise.race([p1,p4]).then(function(res){
		console.log(res);
	}).catch(function(rej){
		console.log(rej); // 時間:500,p4的reject成功
	});
	Promise.race([p2,p3]).then(function(res){
		console.log(res); // 時間:500,p2的resolve成功
	}).catch(function(rej){
		console.log(rej);
	});
	Promise.race([p2,p4]).then(function(res){
		console.log(res); // 時間:500,p2的resolve成功
	}).catch(function(rej){
		console.log(rej);
	});
	Promise.race([p3,p4]).then(function(res){
		console.log(res);
	}).catch(function(rej){
		console.log(rej); // 時間:500,p4的reject失敗
	});

Promise.reject()方法返回一個帶有拒絕原因的Promise對象

  靜態函數Promise.reject返回一個被拒絕的Promise對象。通過使用Error的實例獲取錯誤原因reason對調試和選擇性錯誤捕捉很有幫助。

function resolved(result) {
  console.log('Resolved');
}

function rejected(result) {
  console.error(result);
}

Promise.reject(new Error('fail')).then(resolved, rejected);
// expected output: Error: fail

Promise.resolve(value)

  返回一個以給定值解析后的Promise 對象。如果這個值是一個 promise ,那么將返回這個 promise ;如果這個值是thenable(即帶有"then" 方法),返回的promise會“跟隨”這個thenable的對象,采用它的最終狀態;否則返回的promise將以此值完成。此函數將類promise對象的多層嵌套展平。

// Resolve一個thenable對象
var p1 = Promise.resolve({ 
  then: function(onFulfill, onReject) { onFulfill("fulfilled!"); }
});
console.log(p1 instanceof Promise) // true, 這是一個Promise對象

p1.then(function(v) {
    console.log(v); // 輸出"fulfilled!"
  }, function(e) {
    // 不會被調用
});

// Thenable在callback之前拋出異常
// Promise rejects
var thenable = { then: function(resolve) {
  throw new TypeError("Throwing");
  resolve("Resolving");
}};

var p2 = Promise.resolve(thenable);
p2.then(function(v) {
  // 不會被調用
}, function(e) {
  console.log(e); // TypeError: Throwing
});

// Thenable在callback之后拋出異常
// Promise resolves
var thenable = { then: function(resolve) {
  resolve("Resolving");
  throw new TypeError("Throwing");
}};

var p3 = Promise.resolve(thenable);
p3.then(function(v) {
  console.log(v); // 輸出"Resolving"
}, function(e) {
  // 不會被調用
});

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM