ES6-Promise 對象

1.Promise 的含義

Promise是異步編程的一種解決方案,比傳統的解決方案- -回調函數和事件- - 更合理和更強大。它由社區最早提出和實現,ES6將其寫進入了語言標準,統一了用法,原生提供了Promise對象。

所謂Promise,簡單說就是一個容器,里面保存著某個未來才會結束的時間(通常是一個異步操作)的結果。從語法上說,Promise是一個對象,從它可以獲取異步操作的消息。Promise提共統一的API,各種異步操作都可以用同樣的方法進行處理。

Promise對象有以下各個特點。

(1) 對象的狀態不受外界的影響。Promise對象代表一個異步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態,熱和其他操作都無法改變這個狀態。這也是Promise這個名字的由來,它的英語意思是“承諾”,表示其他手段無法改變。

(2)一旦狀態改變,就不會在改變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:從pending變為fulfilled和從pending變為rejected.只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時候稱為resolved(已定型)。如果改變已經發生了,你再對Promise對象添加回調函數,也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,乳溝你錯過了它,再去監聽,是得不到結果的。

Promise也有一些缺點。首先,無法取消Promise,一旦新建它就會立即執行,無法中途取消。其次,如果不設置回調函數,Promise內部拋出的錯誤,不會反應發哦外部。第三,當初與pending狀態時,無法得到目前進展到哪一個階段。

如果某些事件不斷地地反復發生,一般來說,使用Stream模式是比部署Promise更好的選擇


2.基本用法

ES6規定,Promise對象是一個構造函數,用來生成Promise實例。

下面diamante創造了一個Promise實例

const promise = new Promise(function(resolve,reject){

if(/*異步操作成功*/){

resolve(value);

} else {

reject(error);

}

});

Promise構造函數接受一個函數作為參數,該函數的兩個參數分別是resolve和reject。它們是兩個函數,有javascript引擎提供,不用自己部署。

resolve函數的作用是,將Promise對象的狀態從“未完成”變為“成功”(即從 pending 變為 resolved),在異步操作成功時調用,并將異步操作的結果,作為參數傳遞出去;reject函數的作用是,將Promise對象的狀態從“未完成”變為“失敗”(即從 pending 變為 rejected),在異步操作失敗時調用,并將異步操作報出的錯誤,作為參數傳遞出去。

Promise實例生成以后,可以用then方法分別指定resolved狀態和rejected狀態的回調函數。

promise.then(function(value) {

? // success

}, function(error) {

? // failure

});

then方法可以接受兩個回調函數作為參數。第一個回調函數是Promise對象的狀態變為resolved時調用,第二個回調函數是Promise對象的狀態變為rejected時調用。其中,第二個函數是可選的,不一定要提供。這兩個函數都接受Promise對象傳出的值作為參數。

function timeout(ms) {

return new Promise((resolve,reject) => {

setTimeout(resolve,ms,'done');

});

}

timeout(100).then((value) =>{

console.log(value);

});

上面代碼中,timeout方法返回一個Promise實例,表示一段時間以后才會發生的結果。過了指定的時間以后,Promise實例的狀態變為resolved,就會觸發then方法綁定的回調函數。

Promise新建后就會立即執行。

let promise = new Promise(function(resolve, reject) {

? console.log('Promise');

? resolve();

});

promise.then(function() {

? console.log('resolved.');

});

console.log('Hi!');

// Promise

// Hi!

// resolved

上面代碼中,Promise 新建后立即執行,所以首先輸出的是Promise。然后,then方法指定的回調函數,將在當前腳本所有同步任務執行完才會執行,所以resolved最后輸出。

下面是異步加載圖片的例子。

function loadImageAsync(url) {

return new Promise(function(resolve,reject){

const image = new Image();

image.onload = function() {

resolve(image);

};

image.onerror = function() {

reject(new Error('Could not load image at' + url));

};

image.src = url;

});

}

上面代碼中,使用Promise包裝了一個圖片加載的異步操作。如果加載成功,就調用resolve方法,否則就調用reject方法。

下面是一個用Promise對象實現的Ajax操作的例子。

const getJSON = function(url) {

const promise = new Promise(funciton(resolve,reject){

const handler = function() {

? ? ? if (this.readyState !== 4) {

? ? ? ? return;

? ? ? }

? ? ? if (this.status === 200) {

? ? ? ? resolve(this.response);

? ? ? } else {

? ? ? ? reject(new Error(this.statusText));

? ? ? }

? ? };

? ? const client = new XMLHttpRequest();

? ? client.open("GET", url);

? ? client.onreadystatechange = handler;

? ? client.responseType = "json";

? ? client.setRequestHeader("Accept", "application/json");

? ? client.send();

});

return promis;

};

getJSON("/posts.json").then(function(json) {

console.log('Contents:' + json);

},function(error){

console.log('出錯了',error)

})


3. Promise.prototype.then()

Promise實例具有then方法,也就是說,then方法是定義在原型對象Promise.prototype上的。它的作用是為Promise實例添加狀態改變時的回調函數。

前面說過,then方法的第一個參數是resolved狀態的回調函數,第二個參數(可選)是rejected狀態的回調函數。

then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。因此可以采用鏈式寫法,即then方法后面再調用另一個then方法。

getJSON("/post.json").then(function(json){

return json.post;

}).then(function(post){

//...

})

上面代碼使員工then方法,以此指定了兩個回調函數。第一個回調函數完成以后,會將返回結果作為參數,傳入第二個回調函數。

采用鏈式的then,可以指定一組按照次序調用函數。這時,前一個回調函數,有可能返回的還是一個Promise對象(即有異步操作),這時后一個回調函數,就會等待該Promise對象的狀態反生變化,才會被調用。

getJSON("/post/1.json").then(function(post) {

? return getJSON(post.commentURL);

}).then(function funcA(comments) {

? console.log("resolved: ", comments);

}, function funcB(err){

? console.log("rejected: ", err);

});

上面代碼中,第一個then方法指定的回調函數,返回的是另一個Promise對象。這時,第二個then方法指定的回調函數,就會等待這個新的Promise對象狀態發生變化。如果變為resolved,就調用funcA,如果狀態變為rejected,就調用funcB。

如果采用箭頭函數,上面的代碼可以簡寫的更加簡潔

getJSON("/post/1.json").then(

post => getJSON(post.commentURL);

).then(

comments => console.log("resolved: ", comments),

? err => console.log("rejected: ", err)

);


4.自我理解關于ES6

Promise——承諾

異步:操作之間沒有關系,各自完成各自的,可以同時進行多個操作;

同步:操作之間是相關的,同時只能完成一個操作,必須等前一步完成,才能進行下一步

異步:代碼復雜,操作困難,提高性能

同步:代碼簡單

Promise——消除異步操作

*用同步一樣的方式,來消除異步操作

Promise.all

Promise.race 競速

Promise.race([

$.ajax({url:"http:www.baidu.com"}),

$.ajax({url:"http:www.baidu.com"}),

$.ajax({url:"http:www.baidu.com"}),

$.ajax({url:"http:www.baidu.com"})

]);

eg:

let p = new Promise(function(resolve,reject){

//異步執行

//resolve——成功了

//reject——失敗了

});

Promise.all([

? ? p1,p2

? ? ]).then(function(arr){

? ? ? alert("全部都成功了");

? ? ? let [res1,res2] = arr;

? ? ? console.log(res1);

? ? ? console.log(res2);

? ? },function(){

? ? ? alert("至少有一個成功了");

? ? })

注意:ajax不能再file文件路徑下支持

jquery自己的Promise

有了Promise之后的異步:

Promise.all([$.ajax(),$.ajax()]).then(results=>{

//對了

},err=>{

//錯了

});

eg:

? ? Promise.all([

? ? ? $.ajax({url:"../js/testJson.json",dataType:"json"}),

? ? ? $.ajax({url:"../js/testJson2.json",dataType:"json"}),

? ? ]).then(function(results){

? ? ? let [res1,res2] = results;

? ? ? console.log(res1);

? ? ? console.log(res2);

? ? },function(err){

? ? ? console.log(err)

? ? });


自己封裝Promise自己調用

? ? Promise.all([

? ? ? createPromise("../js/testJson2.json"),

? ? ? createPromise("../js/testJson.json")

? ? ]).then(function(arr){

? ? ? alert("全部都成功了");

? ? ? let [res1,res2] = arr;

? ? ? console.log(res1);

? ? ? console.log(res2);

? ? },function(){

? ? ? alert("至少有一個成功了");

? ? })

? ? function createPromise(url){

? ? ? return new Promise(function(resolve,reject){

? ? ? ? $.ajax({

? ? ? ? ? url:url,

? ? ? ? ? dataType:'json',

? ? ? ? ? success(arr){

? ? ? ? ? ? resolve(arr);

? ? ? ? ? },

? ? ? ? ? err(err){

? ? ? ? ? ? reject(err);

? ? ? ? ? }

? ? ? ? })

? ? ? });

? ? }


原文:阮一峰 ES6

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容

  • Promise 對象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函...
    neromous閱讀 8,719評論 1 56
  • 一、Promise的含義 Promise在JavaScript語言中早有實現,ES6將其寫進了語言標準,統一了用法...
    Alex灌湯貓閱讀 835評論 0 2
  • //本文內容起初摘抄于 阮一峰 作者的譯文,用于記錄和學習,建議觀者移步于原文 概念: 所謂的Promise,...
    曾經過往閱讀 1,246評論 0 7
  • 本文適用的讀者 本文寫給有一定Promise使用經驗的人,如果你還沒有使用過Promise,這篇文章可能不適合你,...
    HZ充電大喵閱讀 7,320評論 6 19
  • 今天添加新的口味,西藍花+菠菜米粉,吃的還可以,前面幾口很不錯,后面就有點搗蛋了
    么么茶63閱讀 442評論 0 0