Promise 對象的含義與基本用法


㈠Promise 的含義

⑴Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。

⑵所謂Promise,簡單說就是一個容器,里面保存着某個未來才會結束的事件(通常是一個異步操作)的結果。

⑶從語法上說,Promise 是一個對象,從它可以獲取異步操作的消息。

⑷Promise 提供統一的 API,各種異步操作都可以用同樣的方法進行處理。

 

㈡Promise對象的特點

⑴對象的狀態不受外界影響。

Promise對象代表一個異步操作,它有三種狀態:

pending:進行中

fulfilled :已經成功

rejected:已經失敗

只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。

 

⑵一旦狀態改變,就不會再變,任何時候都可以得到這個結果。

promise狀態改變:

從pending變為fulfilled

從pending變為rejected。

只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱為 resolved(已定型)

 

㈢promise的缺點

⑴無法取消Promise,一旦新建它就會立即執行,無法中途取消

⑵如果不設置回調函數,Promise內部拋出的錯誤,不會反應到外部

⑶當處於pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)

 

㈣基本用法

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

下面代碼創造了一個Promise實例:

const promise = new Promise(function(resolve, reject) { // ... some code if (/* 異步操作成功 */){ resolve(value); } else { reject(error); } });

★Promise構造函數接受一個函數作為參數,該函數的兩個參數分別是resolvereject

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對象傳出的值作為參數。

 

★下面是一個Promise對象的簡單例子:

function timeout(ms) { return new Promise((resolve, reject) => { setTimeout(resolve, ms, 'done'); }); } timeout(100).then((value) => { console.log(value); });

⑴上面代碼中,timeout方法返回一個Promise實例,表示一段時間以后才會發生的結果。

⑵過了指定的時間(ms參數)以后,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(function(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 promise; }; getJSON("/posts.json").then(function(json) { console.log('Contents: ' + json); }, function(error) { console.error('出錯了', error); });

⑴上面代碼中,getJSON是對 XMLHttpRequest 對象的封裝,用於發出一個針對 JSON 數據的 HTTP 請求,並且返回一個Promise對象。

⑵需要注意的是,在getJSON內部,resolve函數和reject函數調用時,都帶有參數。

 

⑶如果調用resolve函數和reject函數時帶有參數,那么它們的參數會被傳遞給回調函數

reject函數的參數通常是Error對象的實例,表示拋出的錯誤;

resolve函數的參數除了正常的值以外,還可能是另一個 Promise 實例

示例:

const p1 = new Promise(function (resolve, reject) { // ... }); const p2 = new Promise(function (resolve, reject) { // ...  resolve(p1); })

①上面代碼中,p1p2都是 Promise 的實例,但是p2resolve方法將p1作為參數

    即一個異步操作的結果是返回另一個異步操作

②注意,這時p1的狀態就會傳遞給p2,也就是說,p1的狀態決定了p2的狀態

③如果p1的狀態是pending,那么p2的回調函數就會等待p1的狀態改變

④如果p1的狀態已經是resolved或者rejected,那么p2的回調函數將會立刻執行

 

★下面代碼中

⑴p1是一個 Promise,3 秒之后變為rejected

⑵p2的狀態在 1 秒之后改變,resolve方法返回的是p1

⑶由於p2返回的是另一個 Promise,導致p2自己的狀態無效了,由p1的狀態決定p2的狀態。

⑷所以,后面的then語句都變成針對后者(p1)。

⑸又過了 2 秒,p1變為rejected,導致觸發catch方法指定的回調函數。

const p1 = new Promise(function (resolve, reject) { setTimeout(() => reject(new Error('fail')), 3000) }) const p2 = new Promise(function (resolve, reject) { setTimeout(() => resolve(p1), 1000) }) p2 .then(result => console.log(result)) .catch(error => console.log(error)) // Error: fail

⑹注意,調用resolvereject不會終結 Promise 的參數函數的執行

 

★下面代碼中

⑴調用resolve(1)以后,后面的console.log(2)還是會執行,並且會首先打印出來。

⑵這是因為立即 resolved 的 Promise 是在本輪事件循環的末尾執行,總是晚於本輪循環的同步任務。

new Promise((resolve, reject) => { resolve(1); console.log(2); }).then(r => { console.log(r); }); // 2 // 1

 

★一般來說,調用resolvereject以后,Promise 的使命就完成了,

后繼操作應該放到then方法里面,而不應該直接寫在resolvereject的后面

所以,最好在它們前面加上return語句,這樣就不會有意外。

new Promise((resolve, reject) => { return resolve(1); // 后面的語句不會執行 console.log(2); })

 

 

來自:http://es6.ruanyifeng.com/?search=fetch&x=0&y=0#docs/promise


免責聲明!

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



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