您好,登錄后才能下訂單哦!
這篇文章主要講解了“javascript中的糖衣語法Promise對象怎么使用”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“javascript中的糖衣語法Promise對象怎么使用”吧!
最初javascript的異步實現(xiàn)就是使用回調(diào)函數(shù)?;卣{(diào)地獄就是:一個函數(shù)需要等它的回調(diào)函數(shù)(或者回調(diào)和回調(diào)的回調(diào)...)執(zhí)行完畢之后再執(zhí)行。簡單來說,回調(diào)函數(shù)里面嵌套回調(diào)函數(shù)
。而因為回調(diào)地獄的問題,Promise就出現(xiàn)了。我們看看什么是回調(diào)地獄:
// 回調(diào)地獄 //地獄回調(diào) setTimeout(function () { //第一層 console.log(1);//等4秒打印1,然后執(zhí)行下一個回調(diào)函數(shù) setTimeout(function () { //第二層 console.log(2);//等3秒打印2,然后執(zhí)行下一個回調(diào)函數(shù) setTimeout(function () { //第三層 console.log(3);//等2秒打印3,然后執(zhí)行下一個回調(diào)函數(shù) setTimeout(function () { //第四層 console.log(4);//等1秒打印4 }, 1000) }, 2000) }, 3000) }, 4000)
可看出回調(diào)地獄的特點
:
1.難以復用
2.堆棧信息被斷開
3.借助外層變量
回調(diào)地獄是為了讓我們代碼執(zhí)行順序的一種操作(解決異步),但是它會使我們的可讀性非常差。當你有100個,1000個...,代碼會不斷右移,不夠優(yōu)雅,也會影響性能。嵌套和縮進只是回調(diào)地獄的一個梗而已,它導致的問題遠非嵌套導致的可讀性降低而已。接下里我們今天的目的,就是將上面的回調(diào)地獄用Promise解決。
Promise的基本語法
:Promise函數(shù)接收一個函數(shù)作為參數(shù),這個函數(shù)有兩個參數(shù),一個是成功函數(shù)(resolve),一個是失敗函數(shù)(reject)。Promise的.then接收兩個回調(diào)函數(shù),一個是成功函數(shù)的回調(diào),一個是失敗函數(shù)的回調(diào)。這兩個函數(shù)可選,不一定要提供
//Promise語法 let myPromise = new Promise(function(resolve, reject) { // "Producing Code"(可能需要一些時間) resolve(); // 成功時 reject(); // 出錯時 }); // "Consuming Code" (必須等待一個兌現(xiàn)的承諾) myPromise.then( function(value) { /* 成功時的代碼 */ }, function(error) { /* 出錯時的代碼 */ } );
特別注意:
(1)Promise對象中的狀態(tài)不會被外界干擾。狀態(tài)的改變?nèi)Q于異步的操作結果。
(2)Promise對象的狀態(tài)一旦被改變,就不會進行再次改變。 例如:
let myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve('ok');//第一次狀態(tài)為成功 reject('no');//不會改變 }) }).then( function (result) { console.log('resolved'); },//成功狀態(tài)執(zhí)行then后面的成功回調(diào)函數(shù) function (error) { console.log('reject'); } ) //resolved
(3)Promise新建后就會立即執(zhí)行,Promise后面的.then是一個異步操作,在事件循環(huán)中叫做“微任務”。會放在同步代碼后面執(zhí)行。 例如:
let myPromise=new Promise((resolve,reject)=>{ console.log('Promise');//1 resolve(); }) .then(()=>{//這里是一個異步操作 console.log('succeed');//3 }) console.log('Promise resolved');//2 // Promise // Promise resolved // succeed
then方法的返回結果是新的Promise實例
,對象狀態(tài)由回調(diào)函數(shù)的執(zhí)行結果決定。then方法后面還可以再調(diào)用另一個then方法,形成鏈條。采用鏈式的then
,可以指定一組按照次序調(diào)用
的回調(diào)函數(shù)。
const p = new Promise((resolve, reject) => { setTimeout(() => { //設置 p 對象的狀態(tài)為失敗,并設置失敗的值 reject("出錯啦!"); }, 1000) }); p.then( function(value){}, function(reason){console.log(reason);} ) .then(()=>{ console.log(123) });
catch()用于指定發(fā)生錯誤時的回調(diào)函數(shù).例如:
const p = new Promise((resolve, reject) => {//p為Promise的實例 setTimeout(() => { //設置 p 對象的狀態(tài)為失敗,并設置失敗的值 reject("出錯啦!");//reject()方法的作用,等同于拋出錯誤 }, 1000) }); // p.then(function(value){},function(reason){ // // console.error(reason); // console.log(reason); // }); p.catch(function (reason) {//相當于上面的.then(...) console.log(reason);//捕獲reject狀態(tài)的值 });
建議總是使用catch()
方法,而不使用then()
方法的第二個參數(shù).
catch()還可以這樣使用:
const myPromise = new Promise(function(resolve, reject) { throw new Error('出錯啦');//從這拋出錯誤,catch()指定的回調(diào)函數(shù)也可以捕獲 }); promise.catch(function(error) { console.log(error); });
finally()
方法用于指定不管 Promise 對象最后狀態(tài)如何,都會執(zhí)行的操作。而且finally
方法總是會返回原來的值。舉個例子:
function a(){ return new Promise((resolve,reject)=>{ resolve('ok') },1000) } function b(){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ reject('no') },1500) }) } function c(){ setTimeout(()=>{ console.log('finally'); },500) } a() .then((res)=>{ console.log(res); return b() }) .catch((err)=>{ console.log(err); }) .finally(c)//參數(shù)不是回調(diào)函數(shù),如果是回調(diào)函數(shù)也不需要帶參 //ok //no //finally //說明finally()照樣執(zhí)行,有打印
將現(xiàn)有對象轉為 Promise 對象,狀態(tài)為resolved
。舉例如下:
let myString='hello'; console.log(myString);//hello const myPromise=Promise.resolve(myString)//帶參 //等同于const myPromise=Promise.resolve('hello') console.log(myPromise);//Promise { 'hello' } myString=Promise.resolve();//不帶參,直接調(diào)用 console.log(myString);//Promise { undefined } myString.then(result=>{//說明myString已經(jīng)是Promise對象了,只有Promise對象才有.then console.log(result);//undefined })
也會返回一個新的 Promise 實例,該實例的狀態(tài)為rejected
。簡單舉例:
// 以上代碼等于 const p=new Promise((resolve,reject)=>{ reject('error') }) p.catch(error=>{ console.log(error);//error }) // 或者 p.then(function(){},function(error){console.log(error);})//error // 或者 p.then(null,function(error){console.log(error);})//error // 或者 p.then(undefined,function(error){console.log(error);})//error
all()是將多個 Promise 實例,包裝成一個新的 Promise 實例。接收一個數(shù)組作為參數(shù),數(shù)組的每一項都是·Promise對象的實例。如果不是,會通過Promise.resolve()將參數(shù)轉為Promise實例,再進行處理。all()用于將多個 Promise 實例,包裝成一個新的 Promise 實例
。
// promise.all() const myPromise1=new Promise((resolve,reject)=>{ resolve('sure'); }) .then(result=>result) const myPromise2=new Promise((resolve,reject)=>{ reject('cancel') }) .then(result=>result) .catch(error=>error)//myPromise2有自己的catch //感興趣的小伙伴可以嘗試,如果刪除myPromise2.catch(...)后Promise.all([myPromise1,myPromise2])會如何? Promise.all([myPromise1,myPromise2])//myPromise1,myPromise2都處于成功狀態(tài) .then(result=>{console.log(result);})//走這里 [ 'sure', 'cancel' ] .catch(error=>{console.log(error);})
race()是將多個 Promise 實例,包裝成一個新的 Promise 實例。接收一個數(shù)組作為參數(shù),數(shù)組的每一項都是·Promise對象的實例。如果不是,會通過promise.resolve()將參數(shù)轉為Promise實例,再進行處理。只要參數(shù)的Promise實例有一個率先改變狀態(tài),則狀態(tài)改變
。例如:
const myPromise2 = new Promise((resolve, reject) => { setTimeout(()=>{ reject('cancel') },3000) //如果將時間改為<2000,Promise.race([myPromise1, myPromise2])走哪一步呢? }) .then(result => result) .catch(error => error) const myPromise1 = new Promise((resolve, reject) => { setTimeout(()=>{ resolve('sure'); },2000)//myPromise1比myPromise2更先改變狀態(tài) }) .then(result => result) Promise.race([myPromise1, myPromise2]) .then(result => { console.log(result); })//走這里,sure .catch(error => { console.log(error); })
簡要說一下const p1=Promise.all([promise1,promise2,promise3]) 和const p2=Promise.race([promise1,promise2,promise3])的
區(qū)別
:--前者Promise的實例狀態(tài)都為resolved時,p1調(diào)用.then()里面成功時的回調(diào)函數(shù);如果實例狀態(tài)有一個為rejected,p1調(diào)用.then()里面失敗時的函數(shù)或者走.catch()
--后者注重時序,如果率先改變狀態(tài)的實例為resolved,則p2為reslove狀態(tài);否則,為reject狀態(tài)。
<head> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script> </head> <body> <div class="name"> <audio id="audio" controls></audio> </div> <script> function getSong() { return new Promise((resolve, reject) => { $.ajax({ url: 'https://www.fastmock.site/mock/c024e8920dd6003c63dcd9ed2bbf6cb9/music/music', dataType: 'json', success(res) { console.log(res); url = res[0].url; } }) resolve(); }) } function playSong() { let audio = document.getElementById('audio'); window.addEventListener('click', function () { audio.src = url; audio.play() }) } getSong().then(playSong()) </script> </body>
// 引入fs模塊 const fs=require('fs'); // 使用Promise封裝 const P=new Promise(function(resolve,reject){ fs.readFile('./text/2.md',(err,data)=>{ // 如果地址錯誤,拋出異常 if(err) reject(err) ; // 如果成功,輸出內(nèi)容 resolve(data); }); }); P.then(function(value){ console.log(value.toString()); },function(reason){ console.log("defeat!!!!"); });
<body> <img src="https://cache.yisu.com/upload/information/20220721/112/57791.jpg" alt="風景" id="myImage"> <script> const preloadImage = function (path) { return new Promise(function (resolve, reject) { const image = new Image(); // 圖片加載成功 image.onload=()=>{ resolve(image) } // 圖片加載失敗 image.onerror=()=>{ reject('sorry,cannot loding picture') }; image.src = path; }); }; // 獲取圖片DOM節(jié)點 var preImage=document.getElementById('myImage') // 圖片預加載 preloadImage('https://cache.yisu.com/upload/information/20220721/112/57792.jpg') .then(targetImage=> // 點擊頁面切換圖片,讓圖片加載 window.onclick=function(){ setTimeout(()=>{ preImage.src=targetImage.src },1000) } ) </script> </body>
//例如將微信小程序里的showModal進行Promise封裝,那么在任何需要用到此函數(shù)的直接引入就很方便了 // promise形式 封裝 showModal export const showModal=({content})=>{ return new Promise((resolve,reject)=>{ wx.showModal({ title:'提示', content:content, success: (result) => { resolve(result); }, fail: (err) => { reject(err); } }); }) }
1.無法取消Promise,一旦新建它就會立即執(zhí)行,無法中途取消
2.如果不設置回調(diào)函數(shù),Promise內(nèi)部拋出的錯誤,不會反映到外部
3.當處于pending狀態(tài)時,無法得知目前進展到哪一個階段,是剛剛開始還是即將完成
感謝各位的閱讀,以上就是“javascript中的糖衣語法Promise對象怎么使用”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對javascript中的糖衣語法Promise對象怎么使用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。