摘要:說到異步操作,可能想到的是這樣以的為例對于的操作來說,是一個異步的過程,通過回調函數,在得到返回的時候才會去執行操作。
瀏覽器支持
http://caniuse.com/promises/embed/agents=desktop
Promise是抽象異步處理對象以及對其進行各種操作的組件。
說到 javascript 異步操作,可能想到的是這樣:
// 以 jQuery 的 ajax 為例 $.get("/get_url", function(result, status) { if(status == "success") { alert("success"); } if(status == "error") { alert("error"); } });
對于 ajax 的 get 操作來說,是一個異步的過程,通過回調函數,在得到返回的時候才會去執行操作。
但是試想一下當操作越來越多,回調里面還要回調的時候,一層層回調函數是不是讓人抓狂,不論在代碼可讀性還是編寫效率來看都是很麻煩的。
看一下我們用 Promise 可以怎么做一個異步的操作:
// 這個 getData 是我們預先實例好的一個 Promise 對象,如何處理這個對象我們這里不討論 var promise = getData("/get_url");![圖片描述][3] promise.then(function(result) { console.log(result); }).catch(function(error) { console.log(error); });
這樣的風格是不是會更好呢,執行一個 promise,然后 then 里面傳入回調函數,如果愿意,我們可以在 then 后面再更很多個 then,catch 可以捕捉錯誤,看起來代碼清晰簡明多了。
所以,promise的功能是可以將復雜的異步處理輕松地進行模式化。
new Promise(executor); new Promise(function(resolve, reject) { ... });
這里的 executor 是我們實例化一個 promise 對象時應該傳入的參數,這個參數只一個函數,這個函數接受兩個參數 resolve和reject。
兩個方法:
resolve(result) 在 promise 中執行這個方法表示成功,會在執行之后執行后面的 then 所傳入的函數,它接受到的參數也會被 then 里面的函數接受到,一般來說參數為執行結果成功時候的數據;
reject(error) 在 promise 中執行這個方法表示失敗,他一般接受一個 error 錯誤參數,會被后面的 catch 捕捉到錯誤執行。
demo:
var testFoo = function() { return new Promise(function(resolve, reject) { setTimeout(function() { resolve("success"); }, 2000); }); }; testFoo().then(function(result) { console.log(result); }).catch(function(error) { console.log(error); });
在這里我們定義了一個 testFoo 函數,這個函數返回一個Promise的實例化對象,兩秒之后會執行resolve("success");,表示成功,傳入一個參數,在兩秒之后,我們then里面傳入的函數執行了,接收到了剛剛那個參數;但是catch里面的函數并沒有執行,因為我們沒有在 promise 里面執行拒絕操作。
如果我們在四秒之后執行 reject 操作呢:
var testFoo = function() { return new Promise(function(resolve, reject) { setTimeout(function() { resolve("success"); }, 2000); setTimeout(function() { reject("error"); }, 4000); }); }; testFoo().then(function(result) { console.log(result); }).catch(function(error) { console.log(error); });
貌似只出現resolve的結果,因為一個 promise 沒辦法做多次結果操作。
我們就這樣:
var testFoo = function() { return new Promise(function(resolve, reject) { setTimeout(function() { reject("error"); }, 4000); }); }; testFoo().then(function(result) { console.log(result); }).catch(function(error) { console.log(error); });
現在結果如我們所預料了。
PromiseStatus 狀態狀態分為三種:
fulfilled - Fulfilled 已完成,在 resolve時,調用 then 的 onFulfilled函數;
Rejected - Rejected 拒絕,在reject時,調用 then 的 onRejected函數,或者 catch 里面的函數;
unresolved - Pending 等待,是 promise 初始化的時候的狀態。
promise 的 初始化狀態為 unresolved,根據異步結果變為 fulfilled 或者 Rejected,一旦變為其中一個就不可改變,這也是我們之前上面為什么執行了 resolve 之后再執行 reject 而沒有結果的原因了。
方法概述 快捷方法Promise.resolve() 這個是promise的靜態方法
Promise.resolve(10).then(function(value){ console.log(value); });
這個方法會讓 Promise 立即進入 fulfilled 狀態,一般用來測試用。
Promise.reject()相應著我們有這個方法
Promise.reject("err").catch(function(err){ console.log(err); });實例方法
then(onFulfilled, onRejected)這個方法具體是這樣的,傳入兩個函數,一個處理fulfilled狀態,另一個處理Rejected狀態,一般使用我們只傳入第一個函數,第二個放在 catch 來處理。
catch(onRejected)處理Rejected狀態,可以這么理解catch(onRejected)=promise.then(undefined, onRejected)。
鏈式調用看看這個 demo:
var testFoo = function() { return new Promise(function(resolve, reject) { setTimeout(function() { resolve(1); }, 2000); }); }; testFoo().then(function(result) { console.log(result); return ++result; }).then(function(result) { console.log(result); return ++result; }).then(function(result) { console.log(result); return ++result; }).catch(function(error) { console.log(error); }); // 1 // 2 // 3
可以看見結果,這個方法的流程是什么樣的呢?
第一個 then 函數和之前講的一樣,處理 promise 的 fulfilled,第二個 then 的函數是處理前一個 then 函數處理完的結果,他們之間參數傳遞的途徑是前一個 then 函數 return 一個數據,然后后一個 then 函數接受到這個參數。
如果你愿意,可以再后面加很多很多個 then,他們的流程主要是這樣。
如果我們把 catch 提前呢?
var testFoo = function() { return new Promise(function(resolve, reject) { setTimeout(function() { resolve(1); }, 2000); }); }; testFoo().then(function(result) { console.log(result); return ++result; }).then(function(result) { console.log(result); return ++result; }).catch(function(error) { console.log(error); }).then(function(result) { console.log(result); return ++result; }); // 1 // 2 // 3
可以看出,結果一樣,說明catch只會在發生 reject 的時候調用。
那如果在中間的一個 then 中拋出一個異常呢?
var testFoo = function() { return new Promise(function(resolve, reject) { setTimeout(function() { resolve(1); }, 2000); }); }; testFoo().then(function(result) { console.log(result); return ++result; }).then(function(result) { console.log(result); throw new Error("throw Error") return ++result; }).then(function(result) { console.log(result); return ++result; }).catch(function(error) { console.log(error); }); // 1 // 2 // Error: throw Error
我們在第二個then中拋出一個異常,而后立即被 catch 捕捉到,第三個 then 并沒有執行。
到這里我們想一下從then的傳參和捕捉異常來看,新加一個 then 只是注冊了一個回調函數那么簡單嗎?
不不不,每次調用then都會返回一個新創建的promise對象,這就解釋了上面的一切原因。
試想一個場景,我們執行多個異步操作(ajax等等),但是我們想在這幾個操作都完成的時候才去執行一個函數。
如果按照傳統的方法來做,代碼會很亂很散,關鍵不優雅。讓我們嘗試用 promise 。
先看這個 demo
var testFoo = function(time, value) { return new Promise(function(resolve, reject) { setTimeout(function() { resolve(value); }, time * 1000); }); }; var tasks = { task1: function() { return testFoo(1, 2); }, task2: function() { return testFoo(1.3, 3); }, task3: function() { return testFoo(1.5, 1); } }; var main = function() { function recordValue(results, value) { results.push(value); console.log(value); console.log(results); return results; } var pushValue = recordValue.bind(null, []); return tasks.task1().then(pushValue).then(tasks.task2).then(pushValue).then(tasks.task3).then(pushValue); }; main().then(function(value) { console.log(value); }); // [2, 3, 1]
這么實現明顯看起來凌亂,特別對于 main 函數,可讀性也比較差。
那么有沒有更優雅的方法呢,答案:有!?。
Promise.all 方法接受一個以 promise 對象為元素的數組,在全部執行操作完成后才回調用then里面的方法,看代碼:
var testFoo = function(time, value) { return new Promise(function(resolve, reject) { setTimeout(function() { resolve(value); }, time * 1000); }); }; var tasks = { task1: function() { return testFoo(1, 2); }, task2: function() { return testFoo(1.3, 3); }, task3: function() { return testFoo(1.5, 1); } }; var main = function() { return Promise.all([tasks.task1(), tasks.task2(), tasks.task3()]); } main().then(function(result) { console.log(result); }); // [2, 3, 1]
我們吧要執行的 promise 對象作為數組的元素傳給 Promise.all(),Promise.all().then()里面定義的函數接受到一個數組,元素是這幾個操作返回的值,順序和 promise 對象放入的順序一樣,比如第一個 promise 對象返回的值是2,那么結果的第一個元素就是2。
并且每一個promise是同時執行的--并發。
在所有 promise 的狀態為 FulFilled 的時候才會去執行 then 里面的函數。
那么捕捉異常呢?
修改一下例子:
var testFoo = function(time, value, err) { return new Promise(function(resolve, reject) { setTimeout(function() { if(err) { reject(err); return false; } resolve(value); }, time * 1000); }); }; var tasks = { task1: function() { return testFoo(1, 2, "error"); }, task2: function() { return testFoo(1.3, 3, "error1"); }, task3: function() { return testFoo(1.5, 1); } }; var main = function() { return Promise.all([tasks.task1(), tasks.task2(), tasks.task3()]); } main().then(function(result) { console.log(result); }).catch(function(err) { console.log(err); }); // [2, 3, 1]
我們讓其中2 promise 個拋出異常,看到捕捉到了那個異常,而且是捕捉到第一個異常就停止了。
說明 all 的操作是當所有 promise 狀態為 FulFilled 的時候才會執行 then 的操作。而一旦有一個 Rejected 就catch這個異常,并且停止。
他和 Promise.all 一樣,接受一個 promise 對象組成的數組,也是并發執行,但是 Promise.race 是只要有一個promise對象進入 FulFilled 或者 Rejected 狀態的話,就會繼續進行后面的處理。
var testFoo = function(time, value) { return new Promise(function(resolve, reject) { setTimeout(function() { resolve(value); }, time * 1000); }); }; var tasks = { task1: function() { return testFoo(1, 2); }, task2: function() { return testFoo(1.3, 3); }, task3: function() { return testFoo(1.5, 1); } }; var main = function() { return Promise.race([tasks.task1(), tasks.task2(), tasks.task3()]); } main().then(function(result) { console.log(result); }); // 2
可以看到,task1 最先完成,然后就拿到他的值進行 then 操作。
原文來自我的博客 http://qiutc.me/post/promise-learn-note.html
歡迎大家關注~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87729.html
摘要:是一個注冊在指定源和路徑下的事件驅動。可以提供有效有效的離線體驗,攔截網絡請求。出于安全原因,要求必須在下才能運行。返回一個對象,的結果是對象值對象組成的數組。當事件的處理程序執行完畢后,可以認為安裝完成了。 在前端越來越重的這個時代,頁面加載速度成為了一個重要的指標。對于這個問題,業界也有一些解決方案。 瀏覽器緩存、協議緩存、強緩存 懶加載(首屏) CDN 多域名突破下載并發限制。...
摘要:是一個注冊在指定源和路徑下的事件驅動。可以提供有效有效的離線體驗,攔截網絡請求。出于安全原因,要求必須在下才能運行。返回一個對象,的結果是對象值對象組成的數組。當事件的處理程序執行完畢后,可以認為安裝完成了。 在前端越來越重的這個時代,頁面加載速度成為了一個重要的指標。對于這個問題,業界也有一些解決方案。 瀏覽器緩存、協議緩存、強緩存 懶加載(首屏) CDN 多域名突破下載并發限制。...
摘要:把回調函數寫法分離出來,在異步操作執行完后,用鏈式調用的方法執行回調函數,對于多層回調來說,非常的方便,可以繼續在的方法中繼續寫對象并返回,繼續調用來進行回調操作,這就是的作用。 Promise是什么 JS就是操作對象上的屬性和方法,對于一個對象,想要了解,我們可以直接從其身上的屬性和方法入手;直接使用console.dir(對象)打印出來 showImg(https://segm...
摘要:回調函數是的一大特色官方的基本都是以會回調方式傳遞函數返回值。針對這種普遍問題,應勢而生基本用法創建做一些異步操作的事情,然后一切正常的構造器接受一個函數作為參數,它會傳遞給這個回調函數兩個變量和。 Promise 是什么? Promise 對象用來進行延遲(deferred) 和 異步(asynchronous) 計算。 一個 Promise 處于以下三種狀態之一: pend...
摘要:前言筆者的前端開發已經有些時日了,對于一直保留著最初的恐懼,倘若一座不可跨越的高山,思前想后終于邁出最后一步,踏入了開拓自己視野的新視界,希望在看這篇文章的你可以一起跟我動手嘗試。面向的下一代框架。由團隊打造,特點優雅簡潔靈活體積小。 showImg(https://segmentfault.com/img/bVbuorM?w=1514&h=568); 前言 ?????筆者的前端開發已...
閱讀 2247·2021-11-25 09:43
閱讀 2934·2019-08-30 15:52
閱讀 1885·2019-08-30 15:44
閱讀 975·2019-08-30 10:58
閱讀 754·2019-08-29 18:43
閱讀 3209·2019-08-29 18:36
閱讀 2310·2019-08-29 17:02
閱讀 1447·2019-08-29 17:01