1、什麼是Promise
ajax
Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最先提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise對象。 所謂Promise,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。編程
從語法上說,Promise 是一個對象,從它能夠獲取異步操做的消息。Promise 提供統一的 API,各類異步操做均可以用一樣的方法進行處理。promise
如下是MDN對Promise的定義異步
The Promise object is used for asynchronous computations. A Promise represents a single asynchronous operation that hasn't completed yet, but is expected in the future. async
譯文:Promise對象用於異步操做,它表示一個還沒有完成且預計在將來完成的異步操做。異步編程
2、同步和異步函數
咱們知道,JavaScript的執行環境是「單線程」。 spa
所謂單線程,是指JS引擎中負責解釋和執行JavaScript代碼的線程只有一個,也就是一次只能完成一項任務,這個任務執行完後才能執行下一個,它會「阻塞」其餘任務。這個任務可稱爲主線程。 線程
但實際上還有其餘線程,如事件觸發線程、ajax請求線程等。 這也就引起了同步和異步的問題。 對象
同步:
while(true);
console.log("don't execute"); //不會執行
異步:
setTimeout(function() {
console.log('taskA, asynchronous');
}, 0);
console.log('taskB, synchronize');
3、回調函數
回調函數是一段可執行的代碼段,它以「參數」的形式傳遞給其餘代碼,在其合適的時間執行這段(回調函數)的代碼。
var friends = ["Mike", "Stacy", "Andy", "Rick"];
friends.forEach(function (eachName, index){
console.log(index + 1 + ". " + eachName); // 1. Mike, 2. Stacy, 3. Andy, 4. Rick
});
上面例子中的setTimeout就是一個回調函數
再看一次:
setTimeout(function() {
console.log('taskA, asynchronous');
}, 0);
console.log('taskB, synchronize');
4、爲何使用Promise
使用上面的回調函數的方式,若是回調函數嵌套不少層,很容易陷入回調地獄,代碼可讀性差
function fn(callback1, callback2) {
// 耗時操做 let a = 0
for (let i = 0; i < 100; i++) {
a++
}
setTimeout(function() {
callback1(++a)
setTimeout(function() {
callback2(++a)
}, 0)
}, 0)
}
function fn1(a) {
console.log(a)
}
function fn2(a) {
console.log(a)
}
fn(fn1, fn2)
5、Promise基本概念
Promise對象表明一個未完成、但預計未來會完成的操做。
ES6 規定,Promise對象是一個構造函數,用來生成Promise實例。
Promise構造函數接受一個函數做爲參數,該函數的兩個參數分別是resolve和reject。它們是兩個函數,由 JavaScript 引擎提供,不用本身部署。
resolve函數的做用是,將Promise對象的狀態從「未完成」變爲「成功」(即從 pending 變爲 resolved),在異步操做成功時調用,並將異步操做的結果,做爲參數傳遞出去;
reject函數的做用是,將Promise對象的狀態從「未完成」變爲「失敗」(即從 pending 變爲 rejected),在異步操做失敗時調用,並將異步操做報出的錯誤,做爲參數傳遞出去。
它有如下三種狀態:
pending:初始值,不是fulfilled,也不是rejected
fulfilled:表明操做成功
rejected:表明操做失敗
Promise有兩種狀態改變的方式,既能夠從pending轉變爲fulfilled,也能夠從pending轉變爲rejected。
一旦狀態改變,就「凝固」了,會一直保持這個狀態,不會再發生變化。
當狀態發生變化,promise.then綁定的函數就會被調用。
注意:Promise一旦新建就會「當即執行」,沒法取消。
6、Promise基本用法
下面代碼創造了一個Promise實例。
const promise = new Promise(
// executor
function(resolve, reject) {
if (/* 異步操做成功 */){
resolve(value);
} else {
reject(error);
}
});
executor是帶有 resolve 和 reject 兩個參數的函數 。Promise構造函數執行時當即調用executor 函數, resolve 和 reject 兩個函數做爲參數傳遞給executor(executor 函數在Promise構造函數返回所建promise實例對象前被調用)。resolve 和 reject 函數被調用時,分別將promise的狀態改成fulfilled(完成)或rejected(失敗)。executor 內部一般會執行一些異步操做,一旦異步操做執行完畢(可能成功/失敗),要麼調用resolve函數來將promise狀態改爲fulfilled,要麼調用reject 函數將promise的狀態改成rejected。
Promise實例生成之後,能夠用then方法分別指定resolved狀態和rejected狀態的回調函數。
promise.then(function(value) { // success }, function(error) { // failure }); then方法能夠接受兩個回調函數做爲參數。第一個回調函數是Promise對象的狀態變爲resolved時調用,第二個回調函數是Promise對象的狀態變爲rejected時調用。其中,第二個函數是可選的,不必定要提供。這兩個函數都接受Promise對象傳出的值做爲參數。
7、Promise實例應用
//簡單的promise
const promise1 = new Promise(
// executor
function(resolve, reject) {
if (false){
resolve('request success');
} else {
reject('request error');
}
});
promise.then(function(value) {
console.log(value);
}, function(error) {
console.log(error);
});
//then只傳一個方法的狀況
const promise2 = new Promise(
// executor
function(resolve, reject) {
if (false){
resolve('request success');
} else {
reject('request error');
}
});
promise2.then(function(value) {
console.log(value);
});
promise2.catch(function(error) {
console.log(error);
});
//鏈式調用
const promise3 = new Promise(
// executor
function(resolve, reject) {
if (false){
resolve('request success');
} else {
reject('request error');
}
}).then(function(value) {
console.log(value);
}).catch(function(error) {
console.log(error);
});
//嵌套調用
const promise4 = new Promise(
// executor
function(resolve, reject) {
if (true){
resolve('request success');
} else {
reject('request error');
}
}).then(function(value) {
const nextPromise = new Promise(
function(resolve, reject) {
resolve('next request success');
});
return nextPromise;
}).then(function(value) {
console.log(value);
}).catch(function(error){
console.log(error);
});