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