您好,登錄后才能下訂單哦!
本文小編為大家詳細(xì)介紹“Javascript promise異步編程怎么使用”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Javascript promise異步編程怎么使用”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識(shí)吧。
Promise 是異步編程的一種解決方案,可以替代傳統(tǒng)的解決方案–回調(diào)函數(shù)和事件。ES6 統(tǒng)一了用法,并原生提供了 Promise 對(duì)象。作為對(duì)象,Promise 有以下兩個(gè)特點(diǎn):
(1)對(duì)象的狀態(tài)不受外界影響。
(2)一旦狀態(tài)改變了就不會(huì)再變,也就是說任何時(shí)候 Promise 都只有一種狀態(tài)。
Promise 有三種狀態(tài),分別是 Pending (進(jìn)行中)、Resolved (已完成)、Rejected (已失敗)。Promise 從 Pending 狀態(tài)開始,如果成功就轉(zhuǎn)到成功態(tài),并執(zhí)行 resolve 回調(diào)函數(shù);如果失敗就轉(zhuǎn)到失敗狀態(tài)并執(zhí)行 reject 回調(diào)函數(shù)。
可以通過 Promise 的構(gòu)造函數(shù)創(chuàng)建 Promise 對(duì)象
var promise = new Promise((resolve,reject) => { setTimeout(()=>{ console.log("hello world") }, 2000) })
Promise 構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)是 resolve ,reject,它們由 JavaScript 引擎提供。其中 resolve 函數(shù)的作用是當(dāng) Promise 對(duì)象轉(zhuǎn)移到成功,調(diào)用 resolve 并將操作結(jié)果作為其參數(shù)傳遞出去;reject 函數(shù)的作用是當(dāng) Promise 對(duì)象的狀態(tài)變?yōu)槭r(shí),將操作報(bào)出的錯(cuò)誤作為參數(shù)傳遞出去。如下代碼:
function greet(){ var promise = new Promise(function(resolve,reject){ var greet = "hello world" resolve(greet) }) return promise } greet().then(v=>{ console.log(v)//* })
Promise 的 then 方法,promise 的 then 方法帶有一下三個(gè)參數(shù):成功的回調(diào),失敗的回調(diào),前進(jìn)的回調(diào)。一般情況下只需要實(shí)現(xiàn)第一個(gè),后面的是可選的。Promise 中最為重要的狀態(tài),通過 then 的狀態(tài)傳遞可以實(shí)現(xiàn)的回調(diào)函數(shù)鏈?zhǔn)讲僮鞯膶?shí)現(xiàn)。先執(zhí)行以下代碼:
function greet () { var promise = new Promise (function(resolve, reject){ var greet = "hello world" resolve(greet) }) return promise } var p = greet().then(v => { console.log(v) // Promise { <pending> } }) console.log(p) // hello world
catch 用法
function judgeNumber(num){ var promise1 = new Promise(function(resolve,reject){ num =5; if(num<5){ resolve("num小于5,值為:"+num); }else{ reject("num不小于5,值為:"+num); } }); return promise1; } judgeNumber().then( function(message){ console.log(message); } ) .catch(function(message){ console.log(message); })
Promise 的 all 方法提供了并行執(zhí)行異步操作的能力,在 all 中所有異步操作結(jié)束后才執(zhí)行回調(diào)。
function p1(){ var promise1 = new Promise(function(resolve,reject){ console.log("p1的第一條輸出語句"); console.log("p1的第二條輸出語句"); resolve("p1完成"); }) return promise1; } function p2(){ var promise2 = new Promise(function(resolve,reject){ console.log("p2的第一條輸出語句"); setTimeout(()=>{console.log("p2的第二條輸出語句");resolve("p2完成")},2000); }) return promise2; } function p3(){ var promise3 = new Promise(function(resolve,reject){ console.log("p3的第一條輸出語句"); console.log("p3的第二條輸出語句"); resolve("p3完成") }); return promise3; } Promise.all([p1(),p2(),p3()]).then(function(data){ console.log(data); }) p1的第一條輸出語句 p1的第二條輸出語句 p2的第一條輸出語句 p3的第一條輸出語句 p3的第二條輸出語句 p2的第二條輸出語句 ['p1完成', 'p2完成', 'p3完成']
在 all 中的回調(diào)函數(shù)中,等到所有的 Promise 都執(zhí)行完,再來執(zhí)行回調(diào)函數(shù),race 則不同它等到第一個(gè) Promise 改變狀態(tài)就開始執(zhí)行回調(diào)函數(shù)。將上面的all
改為race
,得到
Promise.race([p1(),p2(),p3()]).then(function(data){ console.log(data); })
如何實(shí)現(xiàn)一個(gè) promise
(function(window,undefined){ // resolve 和 reject 最終都會(huì)調(diào)用該函數(shù) var final = function(status,value){ var promise = this, fn, st; if(promise._status !== 'PENDING') return; // 所以的執(zhí)行都是異步調(diào)用,保證then是先執(zhí)行的 setTimeout(function(){ promise._status = status; st = promise._status === 'FULFILLED' queue = promise[st ? '_resolves' : '_rejects']; while(fn = queue.shift()) { value = fn.call(promise, value) || value; } promise[st ? '_value' : '_reason'] = value; promise['_resolves'] = promise['_rejects'] = undefined; }); } //參數(shù)是一個(gè)函數(shù),內(nèi)部提供兩個(gè)函數(shù)作為該函數(shù)的參數(shù),分別是resolve 和 reject var Promise = function(resolver){ if (!(typeof resolver === 'function' )) throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); //如果不是promise實(shí)例,就new一個(gè) if(!(this instanceof Promise)) return new Promise(resolver); var promise = this; promise._value; promise._reason; promise._status = 'PENDING'; //存儲(chǔ)狀態(tài) promise._resolves = []; promise._rejects = []; // var resolve = function(value) { //由於apply參數(shù)是數(shù)組 final.apply(promise,['FULFILLED'].concat([value])); } var reject = function(reason){ final.apply(promise,['REJECTED'].concat([reason])); } resolver(resolve,reject); } Promise.prototype.then = function(onFulfilled,onRejected){ var promise = this; // 每次返回一個(gè)promise,保證是可thenable的 return new Promise(function(resolve,reject){ function handle(value) { // 這一步很關(guān)鍵,只有這樣才可以將值傳遞給下一個(gè)resolve var ret = typeof onFulfilled === 'function' && onFulfilled(value) || value; //判斷是不是promise 對(duì)象 if (ret && typeof ret ['then'] == 'function') { ret.then(function(value) { resolve(value); }, function(reason) { reject(reason); }); } else { resolve(ret); } } function errback(reason){ reason = typeof onRejected === 'function' && onRejected(reason) || reason; reject(reason); } if(promise._status === 'PENDING'){ promise._resolves.push(handle); promise._rejects.push(errback); }else if(promise._status === FULFILLED){ // 狀態(tài)改變后的then操作,立刻執(zhí)行 callback(promise._value); }else if(promise._status === REJECTED){ errback(promise._reason); } }); } Promise.prototype.catch = function(onRejected){ return this.then(undefined, onRejected) } Promise.prototype.delay = function(ms,value){ return this.then(function(ori){ return Promise.delay(ms,value || ori); }) } Promise.delay = function(ms,value){ return new Promise(function(resolve,reject){ setTimeout(function(){ resolve(value); console.log('1'); },ms); }) } Promise.resolve = function(arg){ return new Promise(function(resolve,reject){ resolve(arg) }) } Promise.reject = function(arg){ return Promise(function(resolve,reject){ reject(arg) }) } Promise.all = function(promises){ if (!Array.isArray(promises)) { throw new TypeError('You must pass an array to all.'); } return Promise(function(resolve,reject){ var i = 0, result = [], len = promises.length, count = len //這里與race中的函數(shù)相比,多了一層嵌套,要傳入index function resolver(index) { return function(value) { resolveAll(index, value); }; } function rejecter(reason){ reject(reason); } function resolveAll(index,value){ result[index] = value; if( --count == 0){ resolve(result) } } for (; i < len; i++) { promises[i].then(resolver(i),rejecter); } }); } Promise.race = function(promises){ if (!Array.isArray(promises)) { throw new TypeError('You must pass an array to race.'); } return Promise(function(resolve,reject){ var i = 0, len = promises.length; function resolver(value) { resolve(value); } function rejecter(reason){ reject(reason); } for (; i < len; i++) { promises[i].then(resolver,rejecter); } }); } window.Promise = Promise; })(window);
async 表示這是一個(gè) async 函數(shù), await 只能用在 async 函數(shù)里面,不能單獨(dú)使用
async 返回的是一個(gè) Promise 對(duì)象,await 就是等待這個(gè) promise 的返回結(jié)果后,再繼續(xù)執(zhí)行
await 等待的是一個(gè) Promise 對(duì)象,后面必須跟一個(gè) Promise 對(duì)象,但是不必寫 then(),直接就可以得到返回值
async/await 的優(yōu)點(diǎn)
方便級(jí)聯(lián)調(diào)用:即調(diào)用依次發(fā)生的場(chǎng)景;
同步代碼編寫方式:Promise 使用 then 函數(shù)進(jìn)行鏈?zhǔn)秸{(diào)用,一直點(diǎn)點(diǎn)點(diǎn),是一種從左向右的橫向?qū)懛?;async/await 從上到下,順序執(zhí)行,就像寫同步代碼一樣,更符合代碼編寫習(xí)慣;
多個(gè)參數(shù)傳遞:Promise 的 then 函數(shù)只能傳遞一個(gè)參數(shù),雖然可以通過包裝成對(duì)象來傳遞多個(gè)參數(shù),但是會(huì)導(dǎo)致傳遞冗余信息,頻繁的解析又重新組合參數(shù),比較麻煩;async/await 沒有這個(gè)限制,可以當(dāng)做普通的局部變量來處理,用 let 或者 const 定義的塊級(jí)變量想怎么用就怎么用,想定義幾個(gè)就定義幾個(gè),完全沒有限制,也沒有冗余工作;
同步代碼和異步代碼可以一起編寫:使用 Promise 的時(shí)候最好將同步代碼和異步代碼放在不同的 then 節(jié)點(diǎn)中,這樣結(jié)構(gòu)更加清晰;async/await 整個(gè)書寫習(xí)慣都是同步的,不需要糾結(jié)同步和異步的區(qū)別,當(dāng)然,異步過程需要包裝成一個(gè) Promise 對(duì)象放在 await 關(guān)鍵字后面;
基于協(xié)程:Promise 是根據(jù)函數(shù)式編程的范式,對(duì)異步過程進(jìn)行了一層封裝,async/await 基于協(xié)程的機(jī)制,是真正的“保存上下文,控制權(quán)切換……控制權(quán)恢復(fù),取回上下文”這種機(jī)制,是對(duì)異步過程更精確的一種描述;
async/await 是對(duì) Promise 的優(yōu)化:async/await 是基于 Promise 的,是進(jìn)一步的一種優(yōu)化,不過在寫代碼時(shí),Promise 本身的 API 出現(xiàn)得很少,很接近同步代碼的寫法
讀到這里,這篇“Javascript promise異步編程怎么使用”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。