摘要:對比回調函數和暫時不管是什么,先看一下下面的代碼,看一看的好處。回調函數執行一次首先,定義一個回調函數,調用一次,看看這個代碼的寫法。上面的代碼中,在方法中需要傳遞兩個回調函數,這樣看著會有點亂。
對比回調函數和Promise
暫時不管Promise是什么,先看一下下面的代碼,看一看Promise的好處。需要特別說明的是,在這個對比的中,Promise和回調都沒有考慮存在異常的情況。
回調函數執行一次首先,定義一個回調函數,調用一次,看看這個代碼的寫法。
"use strict"; // 定義一個計數器,用來統計回調函數執行的次數 let count = 1; /** * 定義一個異步執行函數,參數是回調函數 */ function asyncFunc(callback) { setTimeout(function () { callback(`callback ... 執行了 ${count} 次`); count++; }, 1000); }; // 調用函數 asyncFunc(function(data){ console.log(data); }); /************************************* callback ... 執行了 1 次 *************************************/
如果用Promise改寫,會是什么樣的效果呢?
"use strict"; // 定義一個計數器,用來統計回調函數執行的次數 let count = 1; /** * 定義一個異步執行函數,返回值是一個Promise對象 */ function asyncFunc() { let promise = new Promise(function (resolve, reject) { setTimeout(function () { resolve(`resolve ... 執行了 ${count} 次`); count++; }, 1000); }); return promise; }; // 調用函數 asyncFunc().then(function(data){ console.log(data); }); /************************************* resolve ... 執行了 1 次 *************************************/
怎么感覺代碼更復雜,更加難于理解了?確實,在定義函數的時候,需要返回一個Promise對象,增加了代碼量,看著沒什么優勢。從這點來看,學這個東西,完全沒有必要啊。
別著急,接著往下走。。。。
回調函數執行多次上面的情況只是調用一次函數,那么調用多次呢?比如調用個五次、七次。下面咱們看看調用七次的情況。
首先,還是先看看使用回調函數的情況:
"use strict"; // 定義一個計數器,用來統計回調函數執行的次數 let count = 1; /** * 定義一個異步執行函數,參數是回調函數 */ function asyncFunc(callback) { setTimeout(function () { callback(`callback ... 執行了 ${count} 次`); count++; }, 1000); }; // 調用函數 asyncFunc(function (data) { // 第一次調用 console.log(data); asyncFunc(function (data) { // 第二次調用 console.log(data); asyncFunc(function (data) { // 第三次調用 console.log(data); asyncFunc(function (data) { // 第四次調用 console.log(data); asyncFunc(function (data) { // 第五次調用 console.log(data); asyncFunc(function (data) { // 第六次調用 console.log(data); asyncFunc(function (data) { // 第七次調用 console.log(data); }); }); }); }); }); }); }); /************************************* callback ... 執行了 1 次 callback ... 執行了 2 次 callback ... 執行了 3 次 callback ... 執行了 4 次 callback ... 執行了 5 次 callback ... 執行了 6 次 callback ... 執行了 7 次 *************************************/
看著挺好看,但是,當回調更多的時候,如何分清是哪個回調,又怎么判斷哪個括號對應哪句代碼呢?其實這就是一個回調地獄,這樣的代碼可讀性差。
這個時候,Promise就可以發揮作用了。
看了回調函數,再來看看使用Promise的情況:
"use strict"; // 定義一個計數器,用來統計回調函數執行的次數 let count = 1; /** * 定義一個異步執行函數,返回值是一個Promise對象 */ function asyncFunc() { let promise = new Promise(function (resolve, reject) { setTimeout(function () { resolve(`resolve ... 執行了 ${count} 次`); count++; }, 1000); }); return promise; }; // 調用函數 asyncFunc() // 第一次調用 .then(function (data) { console.log(data); return asyncFunc(); // 第二次調用 }) .then(function (data) { console.log(data); return asyncFunc(); // 第三次調用 }) .then(function (data) { console.log(data); return asyncFunc(); // 第四次調用 }) .then(function (data) { console.log(data); return asyncFunc(); // 第五次調用 }) .then(function (data) { console.log(data); return asyncFunc(); // 第六次調用 }) .then(function (data) { console.log(data); return asyncFunc(); // 第七次調用 }) .then(function (data) { console.log(data); }); /************************************* resolve ... 執行了 1 次 resolve ... 執行了 2 次 resolve ... 執行了 3 次 resolve ... 執行了 4 次 resolve ... 執行了 5 次 resolve ... 執行了 6 次 resolve ... 執行了 7 次 *************************************/
會發現,是用了Promise代碼可讀性變得很好,以后也便于修改。
用Promise包裝舊回調寫法現在可以看出Promise的好處,如果想以后都使用Promise,可否實現?
肯定可以實現啊,下面就使用Promise來包裝上面的回調函數。
使用Promise包裹的時候,只需要經過下面幾個步驟:
定義一個函數,返回Promise對象
在Promise對象中調用異步執行函數,參數是創建Promise對象時傳遞的函數
"use strict"; // 定義一個計數器,用來統計回調函數執行的次數 let count = 1; /** * 定義一個異步執行函數,參數是回調函數 */ function asyncFunc(callback) { setTimeout(function () { callback(`callback ... 執行了 ${count} 次`); count++; }, 1000); }; /** * 包裝異步執行函數,返回一個Promise對象 */ function wrapperAsyncFunc() { let promise = new Promise(function (resolve, reject) { asyncFunc(resolve); }); return promise; }; // 調用 wrapperAsyncFunc() .then(function (data) { console.log(data); return wrapperAsyncFunc(); }) .then(function (data) { console.log(data); }); /************************************* callback ... 執行了 1 次 callback ... 執行了 2 次 *************************************/認識Promise
在谷歌瀏覽器中,我們看看Promise都包含什么:
方法概述可以看到,在Promise的prototype上有三個方法,也就是實例對象上有三個方法:
new Promise(function(resolve, reject) { ... } ); promise.then(onFulfilled[, onRejected]); promise.catch(onRejected);
Promise對象本身的方法,就是靜態方法:
Promise.all(iterable); Promise.race(iterable); Promise.reject(reason); Promise.resolve();Promise的三種狀態
在認識這些方法之前,先認識一下Promise的三種狀態:
pending: 初始狀態,創建Promise成功后的狀態
fulfilled: 操作執行成功后的狀態
rejected: 操作執行失敗后的狀態
Promise的實例方法首先,先來創建一個Promise對象,可以根據num的值,來調節執行的函數是resolve還是reject:
new Promise(function(resolve, reject) { ... } );
"use strict"; let num = 3; // 創建一個Promise對象 let promise = new Promise(function (resolve, reject) { if (num > 5) { resolve("success ..."); // 操作執行成功執行的函數 } else { reject("failure ..."); // 操作執行失敗執行的函數 } });
首先明確一點,Promise對象創建的時候,立即執行。可是,既然是立即執行,怎么獲取對應的狀態值呢?下面就要使用then方法了。
promise.then(onFulfilled[, onRejected]);
promise.then(function (data) { console.log(data); }, function (reason) { console.log(reason); });
上面的代碼中,在then方法中需要傳遞兩個回調函數,這樣看著會有點亂。有沒有更優的解決方式?有,這個時候要使用catch方法。
// 把上面的代碼進行簡化 promise .then(function (data) { // 狀態變為fulfilled后執行的回調 console.log(data); }).catch(function (reason) { // 狀態變為rejected后執行的回調 console.log(reason); });Promise的靜態方法
為了方法認識Promise.all和Promise.race,定義三個Promise對象:
let promise1 = new Promise(function (resolve, reject) { setTimeout(function () { resolve("promise1 ..."); console.log("done1 ..."); }, 2000); // 延遲2秒 }); let promise2 = new Promise(function (resolve, reject) { setTimeout(function () { resolve("promise2 ..."); console.log("done2 ..."); }, 4000); // 延遲4秒 }); let promise3 = new Promise(function (resolve, reject) { setTimeout(function () { resolve("promise3 ..."); console.log("done3 ..."); }, 6000); // 延遲6秒 });Promise.all
Promise.all的作用是在參數中的所有Promise對象完全執行完成的時候,才會執行自身的then或catch方法:
Promise .all([promise1, promise2, promise3]) .then(function (data) { console.log(data); }) .catch(function (reason) { console.log(reason); }); /*************************************** done1 ... done2 ... done3 ... [ "promise1 ...", "promise2 ...", "promise3 ..." ] ***************************************/
Promise.all中所有的Promise對象狀態都變為fulfiled狀態時,才會觸發then方法;其中一個變為rejected狀態,那么就觸發catch方法。
需要注意的是,即使觸發了catch方法,其他的Promise對象中的代碼還是會正常執行的。因為這是Promise的特性,創建之后,立即執行。
更改一個Promise對象之后,結果就會成下面的狀態:
let promise2 = new Promise(function (resolve, reject) { setTimeout(function () { reject("promise2 ..."); console.log("done2 ..."); }, 4000); }); /*************************************** done1 ... done2 ... promise2 ... done3 ... ***************************************/Promise.race
Promise.race的作用是在參數中的Promise對象中的一個執行完成的時候,就會執行自身的then或catch方法:
Promise .race([promise1, promise2, promise3]) .then(function (data) { console.log(data); }) .catch(function (reason) { console.log(reason); }); /*************************************** done1 ... promise1 ... done2 ... done3 ... ***************************************/
需要注意的是:Promise.all方法是所有的都執行完成才會觸發then方法,就是不落下任何一個人;而Promise.race方法是有一個執行完成就會觸發then方法,就是看誰跑得快。
后續的兩個方法,以后用到的時候再補充,因為這些內容對現在而言已經夠用了。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88977.html
摘要:意味著操作成功完成。方法接收失敗情況的回調函數作為參數,返回一個對象。參數回調函數不接收任何參數,當對象變成狀態時被調用。現在各個方法的參數返回值功能和使用方法已經有個大概的了解了,為了進一步理解其原理,接下來我打算簡單地實現一下它。 前言 最近幾周參加筆試面試,總是會遇到實現異步和處理異步的問題,然而作者每次都無法完美地回答。在最近一次筆試因為 Promise 而被刷掉后,我終于下定...
摘要:總結用方法創建對象用或添加對象的處理函數它的作用是為實例添加狀態改變時的回調函數。方法是的別名,用于指定發生錯誤時的回調函數。 一、為什么需要Promise Javascript 采用回調函數(callback)來處理異步編程。從同步編程到異步回調編程有一個適應的過程,但是如果出現多層回調嵌套,也就是我們常說的回調金字塔(Pyramid of Doom),絕對是一種糟糕的編程體驗。于是...
摘要:方法是的別名,用于指定發生錯誤時的回調函數。由于字符串不屬于異步操作判斷方法是字符串對象不具有方法,返回實例的狀態從一生成就是,所以回調函數會立即執行。出錯了等同于出錯了出錯了上面的代碼生成一個對象的實例,狀態為,回調函數會立即執行。 引言 Promise 是異步編程的一種解決方案,比傳統的解決方案——回調和事件——更合理且強大。最近的項目要用到這個,就參照阮一峰老師的《ES6標準入門...
摘要:的實現說明沒有執行里的函數說明執行了里的函數說明執行里的函數過程中出現錯誤和執行狀態時的回調函數后返回的結果都需要執行傳進來的對象不能等于當前的對象回調返回的值或者的值是對象時需要等待該對象的狀態變更設置當前狀態的狀態和值執行回調隊列里的函 function resolve_promise_value(promise,value) {//PromiseA+的實現 var th...
摘要:則是把類似的異步處理對象和處理規則進行規范化,并按照采用統一的接口來編寫,而采取規定方法之外的寫法都會出錯。這個對象有一個方法,指定回調函數,用于在異步操作執行完后執行回調函數處理。到目前為止,已經學習了創建對象和用,方法來注冊回調函數。 Promise 本文從js的異步處理出發,引入Promise的概念,并且介紹Promise對象以及其API方法。 js里的異步處理 可以參考這篇文章...
閱讀 2822·2023-04-26 01:00
閱讀 753·2021-10-11 10:59
閱讀 2981·2019-08-30 11:18
閱讀 2677·2019-08-29 11:18
閱讀 1022·2019-08-28 18:28
閱讀 3014·2019-08-26 18:36
閱讀 2135·2019-08-23 18:16
閱讀 1069·2019-08-23 15:56