溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JavaScript中Promise的原理是什么及如何使用

發(fā)布時(shí)間:2023-03-23 14:07:44 來(lái)源:億速云 閱讀:176 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹了JavaScript中Promise的原理是什么及如何使用的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇JavaScript中Promise的原理是什么及如何使用文章都會(huì)有所收獲,下面我們一起來(lái)看看吧。

按照我往常的理解,Promise是一個(gè)構(gòu)造函數(shù),有all、resolve、reject、then、catch等幾個(gè)方法,一般情況下,在涉及到異步操作時(shí)才會(huì)用到Promise。

所以我接下來(lái)先new一個(gè)Promise對(duì)象,并在其中進(jìn)行一些異步操作:

// 使用Promise的時(shí)候一般會(huì)把它包裹在一個(gè)函數(shù)中,并在函數(shù)的最后返回這個(gè)Promise對(duì)象
function runPro()(
    var a = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('work done!');
            resolve('success');
        }, 1000);
    });
    return a;
)
runPro()

在上面的代碼中,Promise的構(gòu)造函數(shù)接收一個(gè)箭頭函數(shù)作為參數(shù),這個(gè)箭頭函數(shù)又有兩個(gè)參數(shù),分別是resolve和reject,我在這個(gè)箭頭函數(shù)中使用setTimeout進(jìn)行了一些異步操作,異步操作中執(zhí)行了resolve方法,并給resolve方法傳了一個(gè)字符串‘success’作為參數(shù)。

執(zhí)行這段代碼會(huì)發(fā)現(xiàn),等待了1秒鐘后(因?yàn)槲以趕etTimeout中設(shè)置的等待時(shí)間是1000毫秒),輸出了‘work done!’。

這時(shí)候并沒(méi)有發(fā)現(xiàn)Promise有什么特別的作用,而且resolve和reject這兩個(gè)的作用也并沒(méi)有體現(xiàn)出來(lái)。

之前我們說(shuō)過(guò)Promise這個(gè)構(gòu)造函數(shù)上有then、catch方法,在上面的代碼片段中,runPro函數(shù)最后return了一個(gè)Promise對(duì)象,所以我們可以在runPro函數(shù)執(zhí)行完成之后使用then對(duì)Promise對(duì)象進(jìn)行進(jìn)一步的操作:

runPro().then((res) => {
    console.log('then:', res);
    //TODO something
});

輸出結(jié)果:

JavaScript中Promise的原理是什么及如何使用

在runPro返回的Promise對(duì)象上直接調(diào)用then方法,then方法接收一個(gè)函數(shù)作為參數(shù)A,并且這個(gè)箭頭函數(shù)也會(huì)接收一個(gè)參數(shù)B,這個(gè)參數(shù)B的值就是前面代碼中resolve方法所傳遞的字符串‘success’。

執(zhí)行代碼,會(huì)在1秒后首先輸出‘work done!’,緊接著輸出‘then: success’。

這個(gè)時(shí)候,就可以簡(jiǎn)單的體現(xiàn)出來(lái)Promise的作用了,在前面的代碼中,then方法就像是Promise的回調(diào)函數(shù),當(dāng)Promise中的異步操作執(zhí)行完之后,通過(guò)鏈?zhǔn)秸{(diào)用的方式執(zhí)行回調(diào)函數(shù)。

這里的關(guān)鍵點(diǎn)就在于鏈?zhǔn)秸{(diào)用上,當(dāng)實(shí)際使用中遇見(jiàn)多層回調(diào)的情況時(shí),Promise的強(qiáng)大之處才能夠體現(xiàn)出來(lái):

function runPro2(){
	var a = new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve('success');
			console.log('this is runPro2');
		}, 1000);
	});
	return a;
};

function runPro3(){
	var a = new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve('success');
			console.log('this is runPro3');
		}, 1000);
	});
	return a;
};

runPro().then(() => {
	return runPro2();
}).then(() => {
	return runPro3();
}).then(() => {
	console.log('all done')
})

到這里為止,大概已經(jīng)明白了,Promise是一個(gè)在異步操作過(guò)程中,等待其中異步操作完成之后執(zhí)行其回調(diào)函數(shù)的一種結(jié)構(gòu)體。但是其中的原理還是模糊不清,其中resolve和reject這兩個(gè)參數(shù)還沒(méi)有搞清楚,只知道在前面的幾個(gè)代碼片段中都調(diào)用了resolve函數(shù),resolve是做什么的并沒(méi)有體現(xiàn)出來(lái)。

關(guān)于resolve和reject,我以前的理解是Promise中的異步操作執(zhí)行成功后調(diào)用resolve函數(shù),異步操作執(zhí)行失敗后調(diào)用reject函數(shù),后來(lái)發(fā)現(xiàn)這種理解其實(shí)是不準(zhǔn)確的。

在理解這兩個(gè)函數(shù)的正確作用之前,我們首先要知道Promise一個(gè)重要的特性:狀態(tài)

Promise的狀態(tài):

一個(gè)Promise對(duì)象的當(dāng)前狀態(tài)必須為以下三種狀態(tài)中的一種:等待(Pending)、完成(Fulfilled)、拒絕(Rejected)。

Pending:

異步操作完成之前,Promise處于等待狀態(tài),這時(shí)候的Promise可以遷移至Fulfilled或者Rejected。

Fulfilled:

異步操作完成之后,Promise可能從Pending狀態(tài)遷移至Fulfilled狀態(tài),F(xiàn)ulfilled狀態(tài)的Promise必須擁有一個(gè)不可變的終值,并且Fulfilled狀態(tài)的Promise不能遷移為其他狀態(tài)。

Rejected:

異步操作完成之后,Promise可能從Pending狀態(tài)遷移至Rejected狀態(tài),Rejected狀態(tài)的Promise必須擁有一個(gè)不可變的拒絕原因,并且Rejected狀態(tài)的Promise不能遷移為其他狀態(tài)。

了解了Promise的三種狀態(tài)之后,我們?cè)賮?lái)說(shuō)說(shuō)resolve和reject這兩個(gè)函數(shù)的作用:

  • resolve函數(shù)將Promise設(shè)置為Fulfilled狀態(tài),reject函數(shù)將Promise設(shè)置為Rejected狀態(tài)。

  • 設(shè)置為Fulfilled或者rejected狀態(tài)后,即表示Promise中的異步操作執(zhí)行完成,這時(shí)程序就會(huì)執(zhí)行then回調(diào)函數(shù)。

  • resolve和reject函數(shù)傳遞的參數(shù),將由then函數(shù)中的箭頭函數(shù)接收。

實(shí)際上,理解Promise的關(guān)鍵點(diǎn)就在于這個(gè)狀態(tài),通過(guò)維護(hù)狀態(tài)、傳遞狀態(tài)的方法來(lái)進(jìn)行及時(shí)的回調(diào)。

所以,如下面代碼所示,當(dāng)使用Promise進(jìn)行異步操作的時(shí)候,其中有幾個(gè)關(guān)鍵點(diǎn)需要特別注意:

在一個(gè)函數(shù)中new了一個(gè)Promise對(duì)象之后,函數(shù)的最后必須把這個(gè)Promise對(duì)象return出來(lái),否則這個(gè)函數(shù)就無(wú)法使用then函數(shù)進(jìn)行回調(diào);

異步操作中必須執(zhí)行resolve或者reject函數(shù),否則這個(gè)Promise一直處于Pending狀態(tài),代碼就不會(huì)執(zhí)行它的回調(diào)函數(shù)。

function runPro(){
	var a = new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve('resolve');
			console.log('this is runPro');
		}, 1000);
	});
	return a;
}

runPro().then((res) => {
	console.log(res);
})

同樣的道理,當(dāng)異步操作執(zhí)行失敗時(shí),代碼通過(guò)執(zhí)行reject函數(shù)的方式,將Promise的狀態(tài)設(shè)置為Rejected,并返回一個(gè)拒絕原因:

function runPro(item){
	var a = new Promise((resolve, reject) => {
		setTimeout(() => {
			if(item >= 18) {
				console.log('item 大于 18');
				resolve('一切正常!');
			}else {
				console.log('item 小于 18');
				reject('18+電影不允許放映!');
			}
		}, 1000);
	});
	return a;
}

runPro(13)
.then((res) => {
	console.log('resolve:',res);
},(rej) => {
	console.log('reject:', rej);
})

我們給runPro函數(shù)傳遞不同的參數(shù),runPro接受參數(shù)后進(jìn)行一個(gè)異步的判斷,如果這個(gè)參數(shù)的值小于18,執(zhí)行reject函數(shù),反之則執(zhí)行resolve函數(shù),異步操作完成之后,執(zhí)行then回調(diào)函數(shù),這里的回調(diào)函數(shù)可以接收兩個(gè)箭頭函數(shù)作為參數(shù),分別對(duì)應(yīng)了resolve函數(shù)的回調(diào)和reject函數(shù)的回調(diào),這兩個(gè)箭頭函數(shù)可以分別拿到resolve和reject傳遞的參數(shù)。

如下面截圖所示,分別給runPro傳遞兩個(gè)不同值后,得到了兩種不同的結(jié)果:

JavaScript中Promise的原理是什么及如何使用

catch函數(shù)的用法

在Promise中,catch函數(shù)可以替代reject函數(shù)使用,用來(lái)指定接收reject的回調(diào):

function runPro(item){
	var a = new Promise((resolve, reject) => {
		setTimeout(() => {
			if(item >= 18) {
				console.log('item 大于 18');
				resolve('一切正常!');
			}else {
				console.log('item 小于 18');
				reject('18+電影不允許放映!');
			}
		}, 1000);
	});
	return a;
}

runPro(13)
.then((res) => {
	console.log('resolve:',res);
})
.catch((rej) => {
	console.log('catch:', rej);
})

如上面代碼所示,對(duì)調(diào)函數(shù)then只有一個(gè)箭頭函數(shù)作為參數(shù),這種情況下,這個(gè)箭頭函數(shù)就被指定用來(lái)接收resolve函數(shù)的回調(diào),而reject函數(shù)的回調(diào)則被catch函數(shù)來(lái)接收:

JavaScript中Promise的原理是什么及如何使用

這個(gè)地方使用catch函數(shù)來(lái)接收reject的回調(diào)有一個(gè)優(yōu)點(diǎn),當(dāng)前面的then回調(diào)函數(shù)中出現(xiàn)位置錯(cuò)誤時(shí),catch函數(shù)可以對(duì)錯(cuò)誤信息進(jìn)行處理,而不會(huì)導(dǎo)致代碼報(bào)錯(cuò)。這個(gè)原理和常用的try/catch語(yǔ)句相同。

function runPro(item){
    var a = new Promise((resolve, reject) => {
        setTimeout(() => {
            if(item >= 18) {
                console.log('item 大于 18');
                resolve('一切正常!');
            }else {
                console.log('item 小于 18');
                reject('18+電影不允許放映!');
            }
        }, 1000);
    });
    return a;
}
runPro(19)
.then((res) => {
    console.log(adc); // 這里的adc是一個(gè)未定義的變量,當(dāng)代碼執(zhí)行到這里時(shí),會(huì)拋出Error信息導(dǎo)致代碼卡死
    console.log('resolve:',res);
}, (rej) => {
    console.log('reject:',rej);
});
runPro(19)
.then((res) => {
    console.log(abc); // 這里的abc是一個(gè)未定義的變量,但是由于后邊使用.catch函數(shù)進(jìn)行了異常捕獲,所以程序不會(huì)報(bào)錯(cuò)。而且錯(cuò)誤原因也會(huì)作為參數(shù)傳遞到后面.catch函數(shù)的參數(shù)中
    console.log('resolve:',res);
})
.catch((rej) => {
    console.log('catch:', rej);
})

JavaScript中Promise的原理是什么及如何使用

all函數(shù) / race函數(shù)并行異步操作

Promise的all函數(shù)和race函數(shù)都提供了并行異步操作的能力,二者的區(qū)別在于,當(dāng)這些并行的異步操作耗時(shí)不同時(shí),all函數(shù)是在所有的異步操作都執(zhí)行完之后才會(huì)執(zhí)行,而race函數(shù)則會(huì)在第一個(gè)異步操作完成之后立即執(zhí)行。

function runPro1(){
	var a = new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve('success');
			console.log('this is runPro1');
		}, 1000);
	});
	return a;
}
function runPro2(){
	var a = new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve('success');
			console.log('this is runPro2');
		}, 2000);
	});
	return a;
};

function runPro3(){
	var a = new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve('success');
			console.log('this is runPro3');
		}, 3000);
	});
	return a;
};

Promise.all([runPro1(), runPro2(), runPro3()])
.then((res) => {
	console.log('all:', res);
})

JavaScript中Promise的原理是什么及如何使用

function runPro1(){
	var a = new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve('success');
			console.log('this is runPro1');
		}, 1000);
	});
	return a;
}
function runPro2(){
	var a = new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve('success');
			console.log('this is runPro2');
		}, 2000);
	});
	return a;
};

function runPro3(){
	var a = new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve('success');
			console.log('this is runPro3');
		}, 3000);
	});
	return a;
};

Promise.races([runPro1(), runPro2(), runPro3()])
.then((res) => {
	console.log('all:', res);
})

JavaScript中Promise的原理是什么及如何使用

如上兩個(gè)代碼片段所示,all函數(shù)和race都接收一個(gè)數(shù)組作為參數(shù),這個(gè)數(shù)組中的值就是我們要進(jìn)行并行執(zhí)行的異步操作。這里我們同樣使用then函數(shù)作為異步操作完成的回調(diào)函數(shù)。同時(shí)我們通過(guò)console輸出發(fā)現(xiàn),在race函數(shù)的回調(diào)函數(shù)開(kāi)始執(zhí)行的時(shí)候,另外兩個(gè)沒(méi)有執(zhí)行完成的異步操作并沒(méi)有停止,依舊在執(zhí)行。

關(guān)于“JavaScript中Promise的原理是什么及如何使用”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“JavaScript中Promise的原理是什么及如何使用”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI