Javascript promise異步編程淺析
promise 是什么
Promise 是異步編程的一種解決方案,可以替代傳統(tǒng)的解決方案–回調函數和事件。ES6 統(tǒng)一了用法,并原生提供了 Promise 對象。作為對象,Promise 有以下兩個特點:
(1)對象的狀態(tài)不受外界影響。
(2)一旦狀態(tài)改變了就不會再變,也就是說任何時候 Promise 都只有一種狀態(tài)。
Promise 有三種狀態(tài),分別是 Pending (進行中)、Resolved (已完成)、Rejected (已失敗)。Promise 從 Pending 狀態(tài)開始,如果成功就轉到成功態(tài),并執(zhí)行 resolve 回調函數;如果失敗就轉到失敗狀態(tài)并執(zhí)行 reject 回調函數。
可以通過 Promise 的構造函數創(chuàng)建 Promise 對象
var promise = new Promise((resolve,reject) => {
setTimeout(()=>{
console.log("hello world")
}, 2000)
})
Promise 構造函數接受一個函數作為參數,該函數的兩個參數是 resolve ,reject,它們由 JavaScript 引擎提供。其中 resolve 函數的作用是當 Promise 對象轉移到成功,調用 resolve 并將操作結果作為其參數傳遞出去;reject 函數的作用是當 Promise 對象的狀態(tài)變?yōu)槭r,將操作報出的錯誤作為參數傳遞出去。如下代碼:
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 方法帶有一下三個參數:成功的回調,失敗的回調,前進的回調。一般情況下只需要實現(xiàn)第一個,后面的是可選的。Promise 中最為重要的狀態(tài),通過 then 的狀態(tài)傳遞可以實現(xiàn)的回調函數鏈式操作的實現(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 中所有異步操作結束后才執(zhí)行回調。
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 中的回調函數中,等到所有的 Promise 都執(zhí)行完,再來執(zhí)行回調函數,race 則不同它等到第一個 Promise 改變狀態(tài)就開始執(zhí)行回調函數。將上面的all改為race,得到
Promise.race([p1(),p2(),p3()]).then(function(data){
console.log(data);
})
如何實現(xiàn)一個 promise
(function(window,undefined){
// resolve 和 reject 最終都會調用該函數
var final = function(status,value){
var promise = this, fn, st;
if(promise._status !== 'PENDING') return;
// 所以的執(zhí)行都是異步調用,保證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;
});
}
//參數是一個函數,內部提供兩個函數作為該函數的參數,分別是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實例,就new一個
if(!(this instanceof Promise)) return new Promise(resolver);
var promise = this;
promise._value;
promise._reason;
promise._status = 'PENDING';
//存儲狀態(tài)
promise._resolves = [];
promise._rejects = [];
//
var resolve = function(value) {
//由於apply參數是數組
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;
// 每次返回一個promise,保證是可thenable的
return new Promise(function(resolve,reject){
function handle(value) {
// 這一步很關鍵,只有這樣才可以將值傳遞給下一個resolve
var ret = typeof onFulfilled === 'function' && onFulfilled(value) || value;
//判斷是不是promise 對象
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中的函數相比,多了一層嵌套,要傳入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 await
async 表示這是一個 async 函數, await 只能用在 async 函數里面,不能單獨使用
async 返回的是一個 Promise 對象,await 就是等待這個 promise 的返回結果后,再繼續(xù)執(zhí)行
await 等待的是一個 Promise 對象,后面必須跟一個 Promise 對象,但是不必寫 then(),直接就可以得到返回值
async/await 的優(yōu)點
方便級聯(lián)調用:即調用依次發(fā)生的場景;
同步代碼編寫方式:Promise 使用 then 函數進行鏈式調用,一直點點點,是一種從左向右的橫向寫法;async/await 從上到下,順序執(zhí)行,就像寫同步代碼一樣,更符合代碼編寫習慣;
多個參數傳遞:Promise 的 then 函數只能傳遞一個參數,雖然可以通過包裝成對象來傳遞多個參數,但是會導致傳遞冗余信息,頻繁的解析又重新組合參數,比較麻煩;async/await 沒有這個限制,可以當做普通的局部變量來處理,用 let 或者 const 定義的塊級變量想怎么用就怎么用,想定義幾個就定義幾個,完全沒有限制,也沒有冗余工作;
同步代碼和異步代碼可以一起編寫:使用 Promise 的時候最好將同步代碼和異步代碼放在不同的 then 節(jié)點中,這樣結構更加清晰;async/await 整個書寫習慣都是同步的,不需要糾結同步和異步的區(qū)別,當然,異步過程需要包裝成一個 Promise 對象放在 await 關鍵字后面;
基于協(xié)程:Promise 是根據函數式編程的范式,對異步過程進行了一層封裝,async/await 基于協(xié)程的機制,是真正的“保存上下文,控制權切換……控制權恢復,取回上下文”這種機制,是對異步過程更精確的一種描述;
async/await 是對 Promise 的優(yōu)化:async/await 是基于 Promise 的,是進一步的一種優(yōu)化,不過在寫代碼時,Promise 本身的 API 出現(xiàn)得很少,很接近同步代碼的寫法
到此這篇關于Javascript promise異步編程淺析的文章就介紹到這了,更多相關Js promise異步內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
javascript的var與let,const之間的區(qū)別詳解
這篇文章主要為大家介紹了?javascript的var與let,const之間的區(qū)別,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2021-12-12

