js異步編程(updating)

js 異步編程方式: Promise船殉,generator/yield,async/await

generator()

  • Generator函數(shù)是一個(gè)狀態(tài)機(jī)洽瞬,封裝了多個(gè)內(nèi)部狀態(tài)。
  • Generator函數(shù)會返回一個(gè)遍歷器對象俄讹,也就是說帽芽,Generator函數(shù)除了狀態(tài)機(jī),還是一個(gè)遍歷器對象生成函數(shù)殃姓。返回的遍歷器對象袁波,可以依次遍歷Generator函數(shù)內(nèi)部的每一個(gè)狀態(tài)瓦阐。
  • Generator函數(shù)可以暫停執(zhí)行的function。

函數(shù)名之前要加星號區(qū)別篷牌,只有調(diào)用next方法時(shí)睡蟋,函數(shù)f才會執(zhí)行

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
// yield是暫停標(biāo)志
}

done屬性的值false,表示遍歷還沒有結(jié)束枷颊。//ture 相反

async await

promise

什么是Promise

Promise最早由社區(qū)提出并實(shí)現(xiàn)戳杀,典型的一些庫有Q,when夭苗, bluebird等信卡;它們的出現(xiàn)是為了更好地解決JavaScript中異步編程的問題,傳統(tǒng)的異步編程最大的特點(diǎn)就是地獄般的回調(diào)嵌套题造,一旦嵌套次數(shù)過多傍菇,就很容易使我們的代碼難以理解和維護(hù)。而Promise則可以讓我們通過鏈?zhǔn)秸{(diào)用的方法去解決回調(diào)嵌套的問題界赔,使我們的代碼更容易理解和維護(hù)丢习,而且Promise還增加了許多有用的特性,讓我們處理異步編程得心應(yīng)手淮悼。

如何創(chuàng)建Promise

ES6給我們提供了一個(gè)原生的構(gòu)造函數(shù)Promise咐低,我們可以看一下這個(gè)構(gòu)造函數(shù):

// 下面的代碼可以直接運(yùn)行在瀏覽器的控制臺中(Chrome瀏覽器)

> typeof Promise
"function" // 可以看出這是一個(gè)構(gòu)造函數(shù)
> Promise
function Promise() { [native code] } // ES6的原生支持

下面我們先來創(chuàng)建一個(gè)promise,下面是一個(gè)簡單的示例:

// 我們先使用ES5的語法
var promise = new Promise(function(resolve, reject) {
    var flag = Math.random();
    setTimeout(function() {
        if(flag) {
            resolve('success');
        }
        else {
            reject('fail');
        }
    }, 1000);
});
console.log(promise); // 在瀏覽器的控制臺運(yùn)行的話袜腥,它返回的是一個(gè)包含了許多屬性的Promise對象见擦;在Node.js環(huán)境中控制臺輸出 Promise { <pending> }。

promise.then(function(result) {
    console.log(result);
}, function(err) {
    console.log(err);
}); // 1s后這里的輸出可能是fail也可能是success

下面來解釋一下上面的代碼:
因?yàn)镻romise是一個(gè)構(gòu)造函數(shù)瞧挤,所以我們使用了new操作符來創(chuàng)建promise。
構(gòu)造函數(shù)Promise的參數(shù)是一個(gè)函數(shù)(暫時(shí)叫它func)儡湾,這個(gè)函數(shù)(func)有兩個(gè)參數(shù)resolvereject特恬,它們分別是兩個(gè)函數(shù),這兩個(gè)函數(shù)的作用就是將promise的狀態(tài)從pending(等待)轉(zhuǎn)換為resolved(已解決)或者從pending(等待)轉(zhuǎn)換為rejected(已失斝炷啤)癌刽。
創(chuàng)建后的promise有一些方法,thencatch尝丐。當(dāng)然我們也可以人為的在Promise函數(shù)上添加一些滿足我們自己需求的方法显拜,方便每一個(gè)promise對象使用。

如果我們使用一些ES6的語法的話爹袁,我們上面的代碼會更加簡潔:

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        Math.random() > 0.5 ? resolve('success') : reject('fail');
    }, 1000)
});

console.log(p);

p.then((result) => {
    console.log(result);
}, (err) => {
    console.log(err);
});

其實(shí)可以這樣理解远荠,Promise函數(shù)體的內(nèi)部包裹著一個(gè)異步的請求或者操作或者函數(shù);然后我們可以在這個(gè)異步的操作完成的時(shí)候使用resolve函數(shù)將我們獲得的結(jié)果傳遞出去失息,或者使用reject函數(shù)將錯(cuò)誤的消息傳遞出去譬淳。

Promise對象的一些方法

Promise對象可以通過使用then方法將上一步返回的結(jié)果獲取過來(不管是resolved還是rejected)档址,可以通過使用catch方法捕獲Promise對象在使用catch之前的異常。

首先來說一下then方法的使用:

let p = new Promise((resolve, reject) => {
   let flag = Math.random() > 0.5 ? true : false;
   if(flag) {
       console.log('使用resolve將promise狀態(tài)從pending變?yōu)閞esolved');
       resolve('success');
   }
   else {
       console.log('使用reject將promise狀態(tài)從pending變?yōu)閞ejected');
       reject('fail');
   }
});

// @1
p.then((result) => {
    console.log('接受resolved的結(jié)果');
    console.log(result);
}, (err) => {
    console.log('捕獲錯(cuò)誤的結(jié)果');
    console.log(err);
});

我們可以看到邻梆,then方法可以接受兩個(gè)函數(shù)作為參數(shù)守伸,第一個(gè)函數(shù)是用來處理resolve的結(jié)果,第二個(gè)是可選的浦妄,用來處理reject的結(jié)果尼摹。也就是說,我們在創(chuàng)建p這個(gè)Promise對象的時(shí)候剂娄,通過函數(shù)resolve傳遞出去的結(jié)果可以被p的第一個(gè)then方法中的第一個(gè)函數(shù)捕獲然后作為它的參數(shù)蠢涝。通過函數(shù)reject傳遞出去的結(jié)果可以被p的第一個(gè)then方法中的第二個(gè)函數(shù)捕獲然后作為它的參數(shù)。

當(dāng)然我們還可以在每一個(gè)then方法中創(chuàng)建新的Promise宜咒,然后將這個(gè)Promise對象返回惠赫,之后我們就可以在后面的then方法中繼續(xù)對這個(gè)對象進(jìn)行操作。下面是一個(gè)簡單的例子:

let p1 = new Promise((resolve, reject) => {
    let flag = Math.random() > 0.5 ? true : false;
    resolve();
});
// @2 使用then方法進(jìn)行鏈?zhǔn)降恼{(diào)用
p1.then(() => {
    return 1;
}).then((result) => {
    console.log(result);
    return 'hello'
}).then((result) => {
    console.log(result);
});

// @3 在then方法內(nèi)部可以再次使用異步的操作
p1.then(() => {
    console.log('******');
    let p1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(123);
        }, 1000);
    });
    return p1;
}).then((result) => {
    console.log(result);
});

從上面的代碼中我們可以看到故黑,一旦創(chuàng)建一個(gè)Promise對象之后儿咱,我們就可以使用then方法來進(jìn)行鏈?zhǔn)降恼{(diào)用,而且我們可以把每一次的結(jié)果都返還給下一個(gè)then方法场晶,然后在下一個(gè)then方法中對這個(gè)值進(jìn)行處理混埠。每一個(gè)then方法中都可以再次新創(chuàng)建一個(gè)Promise對象,然后返還給下一個(gè)then方法處理诗轻。

Promise還有另一個(gè)方法catch钳宪,這個(gè)方法其實(shí)是then方法的一種特例,這個(gè)特例就是:

.then(null, rejection)
相當(dāng)于我們不使用then方法的第一個(gè)函數(shù)扳炬,只是用第二個(gè)函數(shù)吏颖;catch函數(shù)比較簡單,就是用來捕獲之前的then方法里面的異常恨樟,我們可以簡單的來看一個(gè)例子:

let p = new Promise((resolve, reject) => {
resolve();
});
p.then(() => {
console.log('progress...');
}).then(() => {
throw new Error('fail');
}).catch((err) => {
console.log(err);
});
上面代碼的輸出結(jié)果如下:

progress...
VM141:9 Error: fail(…)
我們可以使用catch函數(shù)來捕獲整個(gè)then函數(shù)鏈中的異常半醉。

Promise的一些方法

Promise.all方法用來包裝許多個(gè)Promise實(shí)例,然后組成了一個(gè)新的Promise對象劝术,新的Promise對象的狀態(tài)由前面幾個(gè)被包裹的Promise對象的狀態(tài)決定缩多,如果前面的Promise都被resolve了,那么新的Promise的狀態(tài)也是resolve的养晋;只要有一個(gè)Promise被reject了衬吆,那么組成的新的Promise的狀態(tài)也是reject的。

可以看下面一個(gè)例子:

let arr = [1, 2, 3].map(
    (value) => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(value);
            }, value * 1000);
        });
    }
);

console.log(arr);

let promises = Promise.all(arr)
.then((result) => {
    console.log(result);
}).catch((err) => {
    console.log(err);
});

上面的代碼的輸出結(jié)果如下:

[ Promise { <pending> },
  Promise { <pending> },
  Promise { <pending> } ]
[ 1, 2, 3 ] // 3s后輸出的結(jié)果

Promise.race方法和上面的Promise.all有點(diǎn)類似绳泉,都是包裝許多的Promise對象逊抡,然后組成了一個(gè)新的Promise對象,但是使用Promise.race的含義是:只要包裹的的Promise對象中有一個(gè)的狀態(tài)發(fā)生了改變零酪,那么組成的這個(gè)新的Promise對象的狀態(tài)就是上面那個(gè)率先改變的Promise實(shí)例的狀態(tài)秦忿。

下面是一個(gè)簡單的例子:

let arr = [1, 2, 3].map(
    (value) => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(value);
            }, value * 1000);
        });
    }
);

console.log(arr);

let promises = Promise.race(arr)
    .then((result) => {
        console.log(result);
    }).catch((err) => {
        console.log(err);
    });
上面程序的輸出結(jié)果如下:

[ Promise { <pending> },
  Promise { <pending> },
  Promise { <pending> } ]
1 // 是最先改變狀態(tài)的那個(gè)Promise實(shí)例resolve的值

Promise.resolve方法主要是將一個(gè)值轉(zhuǎn)變?yōu)橐粋€(gè)Promise對象麦射,然后使它具有Promise的一些方法和特性,為了滿足我們一些特殊情況下的要求灯谣。

下面是一個(gè)簡單的例子:

let arr = [null, 0, 'hello',
    { then: function() { console.log(' a thenable obj')}}
];

arr.map((value) => {
        return Promise.resolve(value);
    });

console.log(arr);
上面的輸出結(jié)果如下:

[ null, 0, 'hello', { then: [Function: then] } ]
 a thenable obj // Promise.resolve方法會將具有then方法的對象轉(zhuǎn)換為一個(gè)Promise對象潜秋,然后就立即執(zhí)行then方法。

Promise.reject方法和Promise.resolve方法一樣胎许,只不過通過Promise.reject方法產(chǎn)生的Promise對象的狀態(tài)是rejected的峻呛,下面是一個(gè)示例:

let p = Promise.reject('fail');
p.catch((err) => {
    console.log(err);
}); // fail

async await
fetch 介紹

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市辜窑,隨后出現(xiàn)的幾起案子钩述,更是在濱河造成了極大的恐慌,老刑警劉巖穆碎,帶你破解...
    沈念sama閱讀 211,496評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件牙勘,死亡現(xiàn)場離奇詭異,居然都是意外死亡所禀,警方通過查閱死者的電腦和手機(jī)方面,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,187評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來色徘,“玉大人恭金,你說我怎么就攤上這事」硬撸” “怎么了横腿?”我有些...
    開封第一講書人閱讀 157,091評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長斤寂。 經(jīng)常有香客問我耿焊,道長,這世上最難降的妖魔是什么遍搞? 我笑而不...
    開封第一講書人閱讀 56,458評論 1 283
  • 正文 為了忘掉前任罗侯,我火速辦了婚禮,結(jié)果婚禮上尾抑,老公的妹妹穿的比我還像新娘歇父。我一直安慰自己蒂培,他們只是感情好再愈,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,542評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著护戳,像睡著了一般翎冲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上媳荒,一...
    開封第一講書人閱讀 49,802評論 1 290
  • 那天抗悍,我揣著相機(jī)與錄音驹饺,去河邊找鬼。 笑死缴渊,一個(gè)胖子當(dāng)著我的面吹牛赏壹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播衔沼,決...
    沈念sama閱讀 38,945評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼蝌借,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了指蚁?” 一聲冷哼從身側(cè)響起菩佑,我...
    開封第一講書人閱讀 37,709評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凝化,沒想到半個(gè)月后稍坯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,158評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搓劫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,502評論 2 327
  • 正文 我和宋清朗相戀三年瞧哟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糟把。...
    茶點(diǎn)故事閱讀 38,637評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绢涡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出遣疯,到底是詐尸還是另有隱情雄可,我是刑警寧澤,帶...
    沈念sama閱讀 34,300評論 4 329
  • 正文 年R本政府宣布缠犀,位于F島的核電站数苫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏辨液。R本人自食惡果不足惜虐急,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,911評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望滔迈。 院中可真熱鬧止吁,春花似錦、人聲如沸燎悍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,744評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谈山。三九已至俄删,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背畴椰。 一陣腳步聲響...
    開封第一講書人閱讀 31,982評論 1 266
  • 我被黑心中介騙來泰國打工臊诊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人斜脂。 一個(gè)月前我還...
    沈念sama閱讀 46,344評論 2 360
  • 正文 我出身青樓抓艳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親帚戳。 傳聞我的和親對象是個(gè)殘疾皇子壶硅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,500評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 異步編程對JavaScript語言太重要。Javascript語言的執(zhí)行環(huán)境是“單線程”的销斟,如果沒有異步編程庐椒,根本...
    呼呼哥閱讀 7,301評論 5 22
  • 弄懂js異步 講異步之前,我們必須掌握一個(gè)基礎(chǔ)知識-event-loop蚂踊。 我們知道JavaScript的一大特點(diǎn)...
    DCbryant閱讀 2,706評論 0 5
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持约谈,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠犁钟,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 6,374評論 9 19
  • 本文首發(fā)在個(gè)人博客:http://muyunyun.cn/posts/7b9fdc87/ 提到 Node.js, ...
    牧云云閱讀 1,679評論 0 3
  • 你不知道JS:異步 第三章:Promises 接上篇3-1 錯(cuò)誤處理(Error Handling) 在異步編程中...
    purple_force閱讀 1,391評論 0 2