本文并不提供Promise和async函數(shù)的用法說明,僅嘗試通過簡單的示例代碼對(duì)Promise和async函數(shù)的概念和本質(zhì)作簡單梳理。
Promise和async函數(shù)是為異步而生侍咱,但是,如果將它們和異步劃等號(hào)密幔,可能就有問題了楔脯。
查看原文
先說Promise
定義 promise
// 定義 promise
const promise = new Promise((resolve, reject) => {
console.log('promise start');
// 用一個(gè)for循環(huán)簡單模擬一下大數(shù)據(jù)量處理
for (let index = 0; index < 5; index++) {
console.log('promise process ' + index);
}
console.log('promise end');
})
console.log('1');
// 按照慣例,then 一下
promise.then(()=>{console.log('Promise done')});
console.log('2');
運(yùn)行結(jié)果:
promise start
promise process 0
promise process 1
promise process 2
promise process 3
promise process 4
promise end
1
2
在這個(gè)示例代碼中胯甩,定義Promise的代碼在定義時(shí)就已經(jīng)同步執(zhí)行了昧廷,后面的then調(diào)用沒有任何輸出。
A:"說明什么蜡豹?說明Promise不是異步的,它的定義和執(zhí)行都不是異步的溉苛!"
B:“你胡說镜廉,你連resolve都沒用!”
加入resolve
const promise = new Promise((resolve, reject) => {
console.log('promise start');
for (let index = 0; index < 5; index++) {
console.log('promise process ' + index);
}
// 用resolve拋出一個(gè)值
resolve('promise done');
console.log('promise end');
})
console.log('1');
// then 的回調(diào)函數(shù)中接到resolve拋出的值并輸出到控制臺(tái)
promise.then((v)=>{console.log(v)});
console.log('2');
運(yùn)行結(jié)果:
promise start
Promise0
Promise1
Promise2
Promise3
Promise4
promise end
1
2
promise done
B:“異步了吧愚战?異步了吧娇唯?‘promise done’在2后面出來的齐遵。”
A:“整個(gè)promise執(zhí)行過程是同步的塔插,把返回值異步出來梗摇,頂個(gè)X用!”
B:"......"
B:"我想起來了想许,阮大俠說:“Promise只是個(gè)異步操作容器”伶授,所以你要在Promise中裝個(gè)異步操作進(jìn)去才行!"
塞個(gè)異步操作
const promise = new Promise((resolve, reject) => {
console.log('promise start');
// 這個(gè)setTimeout就是塞進(jìn)來的異步操作
setTimeout(()=>{
// 原來的大數(shù)據(jù)量處理語句移到setTimeout中來
for (let index = 0; index < 5; index++) {
console.log('Promise' + index);
}
// 原來的結(jié)果返回語句也移到setTimeout中來
resolve('promise done');
},1000);
console.log('promise end');
})
運(yùn)行結(jié)果:
promise start
promise end
1
2
Promise0
Promise1
Promise2
Promise3
Promise4
promise done
B:“異步了吧流纹?異步了吧糜烹?整個(gè)業(yè)務(wù)邏輯都是在2后面出來的∈”
A:“是異步了疮蹦,但是setTimeout本身就執(zhí)行了一個(gè)異步操作,干嘛要多此一舉的把它塞進(jìn)Promise里呢茸炒?”
B:“......”
為什么要用Promise
我們?cè)诋惒秸{(diào)用時(shí)經(jīng)常會(huì)遇到"后一個(gè)異步調(diào)用的參數(shù)是前一個(gè)異步調(diào)用的結(jié)果"的情況愕乎,傳統(tǒng)方式寫出來是這樣:
a(參數(shù),function(){
b(result-from-a,function(){
//.....
})
})
a和b嵌套起來了壁公,如果關(guān)聯(lián)關(guān)系更多感论,可能會(huì)出現(xiàn)這種情況:
a(參數(shù),function(){
b(result-from-a,function(){
c(result-from-b贮尖,function(){
d(result-from-c笛粘,function(){
e(result-from-d,function(){
//.....
})
})
})
})
})
這還只是非常理想的單一數(shù)據(jù)獲取情況下的嵌套湿硝,如果有分支嵌套再加上異常處理薪前,那干脆能亂成一鍋粥。這就是那個(gè)有名的“回調(diào)地獄”关斜。
怎么破示括?Promise!
a.then((result-from-a)=>{
return b(result-from-a);
})
.then((result-from-b)=>{
return c(result-from-b);
})
.then((result-from-c)=>{
return d(result-from-c);
})
.then((result-from-d)=>{
return e(result-from-d);
})
.then((result-from-e)=>{
console.log(result-from-e);
})
.catch((error)=>{
console.log(error);
})
這樣舒心多了吧?
所以痢畜,Promise是個(gè)包裝器垛膝,把異步操作包起來,以更易讀更有條理更符合人類思維習(xí)慣的方式讓廣大程序猿(嬡)來寫異步代碼丁稀。如果拋開異步操作使用Promise就是耍流氓。
要點(diǎn)是:Promise是用來包裝異步操作的
再看async函數(shù)
B:”async,就是異步的意思线衫,async函數(shù),當(dāng)然就是異步執(zhí)行的函數(shù)了。這個(gè)不存在二義性吧枯跑?“
A:”這個(gè)......,咱們用代碼說話......“
初探async函數(shù)
// 定義 async 函數(shù)
async function asynFunction(){
console.log('asynFunction begin');
// 還是用一個(gè)for循環(huán)代表大數(shù)據(jù)量處理
for (let index = 0; index < 5; index++) {
console.log('asynFunction process ' + index);
}
console.log('asynFunction end');
}
console.log('1');
// 調(diào)用 async 函數(shù)
asynFunction();
console.log('2');
執(zhí)行結(jié)果:
1
asynFunction begin
asynFunction process 0
asynFunction process 1
asynFunction process 2
asynFunction process 3
asynFunction process 4
asynFunction end
2
B:”這個(gè)......敛助,異步函數(shù)沒有異步執(zhí)行?會(huì)不會(huì)是什么地方寫錯(cuò)了纳击?“
A:”哈哈,加點(diǎn)東西給你看看“
await出場
async function asynFunction(){
console.log('asynFunction begin');
// 加入 await
await 'async go!';
for (let index = 0; index < 5; index++) {
console.log('asynFunction process ' + index);
}
console.log('asynFunction end');
}
console.log('1');
// 調(diào)用 async 函數(shù)
asynFunction();
console.log('2');
執(zhí)行結(jié)果:
1
asynFunction begin
2
asynFunction process 0
asynFunction process 1
asynFunction process 2
asynFunction process 3
asynFunction process 4
asynFunction end
B:"從await開始评疗,后面語句都異步了?難道await表示異步開始的意思百匆?......"
B:"不對(duì)啊,wait是等待的意思加匈,await明明是用來等待異步執(zhí)行結(jié)果的,在這里怎么變成異步開始的標(biāo)志了雕拼?......"
A:"你說對(duì)了纵东,await是用來等待異步執(zhí)行結(jié)果的。但是await在使用時(shí)啥寇,后面需要跟一個(gè)Promise對(duì)象偎球,如果不是,會(huì)被轉(zhuǎn)為Promise對(duì)象辑甜,如上面的await 'async go!'
相當(dāng)于如下代碼:
await new Promise((resolve, reject) => {
resolve('async go!');
})
A:”所以衰絮,await并不是異步開始的標(biāo)志,而是因await對(duì)異步執(zhí)行的等待磷醋,導(dǎo)致await之后語句延后執(zhí)行猫牡。我們?cè)賹懚未a看看......“
引入Promise
function a(arg){
return new Promise((resolve, reject) => {
resolve(arg);
})
}
function b(arg){
return new Promise((resolve, reject) => {
resolve('你好,' + arg);
})
}
async function asynFunction(){
var aResult = await a('北京');
var bResult = await b(aResult);
console.log(bResult);
}
console.log('1');
asynFunction();
console.log('2');
執(zhí)行結(jié)果:
1
2
你好邓线,北京
A:”當(dāng)然淌友,我們往往需要通過async函數(shù)返回需要的數(shù)據(jù)......“
function a(arg){
return new Promise((resolve, reject) => {
resolve(arg);
})
}
function b(arg){
return new Promise((resolve, reject) => {
resolve('你好,' + arg);
})
}
async function asynFunction(){
var aResult = await a('北京');
var bResult = await b(aResult);
// 返回執(zhí)行結(jié)果
return bResult;
}
console.log('1');
// 需要在then()方法中獲取執(zhí)行結(jié)果骇陈,原因是async函數(shù)的返回值同樣會(huì)被包裝成Promise對(duì)象
asynFunction().then((v)=>{console.log(v)});
console.log('2');
執(zhí)行結(jié)果:
1
2
你好震庭,北京
async函數(shù)其實(shí)也是一個(gè)包裝器,async和await配合你雌,包裝的是Promise器联,與Promise相比易讀性更好,更加符合代碼語義。
要點(diǎn)是:async函數(shù)是用來包裝Promise的
總結(jié)
Promise是用來包裝異步操作的主籍,所以僅僅包含同步代碼它是異步不了滴。
Promise把異步操作包裝起來逛球,是為了讓你的異步代碼看起來更直觀更優(yōu)雅千元。
async函數(shù)是用來包裝Promise的,所以僅僅包含同步代碼它也是異步不了滴颤绕。
async函數(shù)把Promise包裝起來幸海,是為了讓你的異步代碼看起來比Promise還要直觀還要
優(yōu)雅,能夠做到望文生義......
本文的初衷其實(shí)是希望大家不要望文生義......>_<