JS:異步總結(jié)

如果需要執(zhí)行一段異步代碼塘幅,js有以下幾種方案:

回調(diào)函數(shù)

setTimeout(function(){
    setTimeout(function(){
        setTimeout(function(){
                ......
        })
    })
})

有一些問(wèn)題:

  • 層層嵌套,代碼難看饥追,不優(yōu)雅
  • try{}cattch()難捕獲異常
  • 不能return

事件監(jiān)聽(tīng)

發(fā)布/訂閱

Promise

  1. Promise是一個(gè)類(lèi)鬼吵,類(lèi)的構(gòu)造函數(shù)接收一個(gè)task任務(wù)函數(shù)边篮,該函數(shù)接收兩個(gè)JavaScript引擎提供的兩個(gè)參數(shù)resolve, reject
  2. 立即執(zhí)行傳入的task函數(shù)
  3. 如果操作(一般是異步操作)成功幢码,調(diào)用resolve方法,并把異步的結(jié)果傳入,如果傳入的是一個(gè)promise尖飞,則自己的狀態(tài)無(wú)效症副,傳入的promise的狀態(tài)決定了該promise的狀態(tài)店雅,如果傳入的不是一個(gè)promise,resolve方法會(huì)把等待狀態(tài)變成成功狀態(tài)(pending -> resolved)贞铣;如果操作(一般是異步操作)失敗闹啦,調(diào)用reject方法,并把異步的結(jié)果傳入,reject方法會(huì)把等待狀態(tài)變成失敗狀態(tài)(pending -> rejected)辕坝。
  4. then方法指定回調(diào)函數(shù)窍奋,接收兩個(gè)回調(diào)函數(shù)resolve, reject。當(dāng)狀態(tài)從pengding->resolved時(shí)酱畅,執(zhí)行resolve琳袄,如果resolve的結(jié)果是一個(gè)promise,這是后面一個(gè)回調(diào)函數(shù)會(huì)等待該promise完成后執(zhí)行纺酸;當(dāng)狀態(tài)從pengding->rejected時(shí)窖逗,執(zhí)行reject。
  5. then方法返回一個(gè)新的Promise實(shí)例(不是原來(lái)的Promise)餐蔬,因此可以鏈?zhǔn)秸{(diào)用碎紊。

下面是模擬ES6,自己代碼代碼實(shí)現(xiàn)Promise:

function Promise(task) {
    var t = this;
    t.value;
    t.statues = "pending";
    t.resolveCallbacks = [];
    t.rejectCallbacks = [];
    function resolve(value){
        if(value instanceof Promise){
            value.then(resolve, reject);
        }else{
            t.statues = "fufilled";
            t.value = value;
            t.resolveCallbacks.forEach(item=>item(value));
        }
    }
    function reject(value){
        if(value instanceof Promise){
            value.then(resolve, reject);
        }else{
            t.statues = "rejected";
            t.value = value;
            t.rejectCallbacks.forEach(item=>item(value));
        }
    }
    try{
        task(resolve, reject);
    }catch(e){
        reject(e);
    }
}
function resolvePromise(x, resolve, reject){
    if(x instanceof Promise){
        if(x.statues == "fufilled"){
            resolve(x.value);
        }else if(x.statues == "rejected"){
            reject(x.value);
        }else{
            x.then(function (y) {
                resolvePromise(y, resolve, reject);
            }, reject)
        }
    }else if(x != null && (typeof x == "object" || typeof x == "function")){
        let then = x.then;
        if(typeof then == "function"){
            x.then.call(x, function (y2) {
                resolvePromise(y2, resolve, reject);
            }, reject)
        }
    }else{
        resolve(x);
    }
}

Promise.prototype = {
    then: function (resolveCall, rejectCall) {
        let t = this;
        let promise2;
        resolveCall = typeof resolveCall == "function" ? resolveCall : function () {
            return t.value;
        }
        rejectCall = typeof rejectCall == "function" ? rejectCall : function () {
            return t.value;
        }
        if(t.statues == "fufilled"){
            promise2 = new Promise(function (resolve, reject) {
                let x = resolveCall(t.value);
                resolvePromise(x, resolve, reject);
            })

        }else if(t.statues == "rejected"){
            promise2 = new Promise(function (resolve, reject) {
                let x = rejectCall(t.value);
                resolvePromise(x, resolve, reject);
            })
        }else if(t.statues == "pending"){
            promise2 = new Promise(function (resolve, reject) {
                t.resolveCallbacks.push(function () {
                    resolvePromise(resolveCall(t.value), resolve, reject);
                });
                t.rejectCallbacks.push(function () {
                    resolvePromise(rejectCall(t.value), resolve, reject);
                });
            })
        }
        return promise2;
    }
}

// 快捷方法
Promise.resolve = function (value) {
    return new Promise(function(resolve, reject){
        resolve(value);
    });
}
Promise.reject = function (value) {
    return new Promise(function(resolve, reject){
        reject(value);
    });
}

// 所有成功resolve樊诺,否則reject
Promise.all = function (promises) {
    if(!Array.isArray(promises)){
        return TypeError("參數(shù)類(lèi)型錯(cuò)誤");
    }
    return new Promise(function (resolve, reject) {
        let result = [];
        let index = 0;
        if(promises.length > 0){
            for(let i = 0; i<promises.length; i++){
                promises[i].then(function (value) {
                    index++;
                    result[i] = value;
                    if(index == promises.length){
                        resolve(result);
                    }
                }, function (value) {
                    reject(value);
                })
            }
        }
    })
}

// 競(jìng)速仗考,誰(shuí)跑得快先返回誰(shuí)
Promise.race = function (promises) {
    if(!Array.isArray(promises)){
        return TypeError("參數(shù)類(lèi)型錯(cuò)誤");
    }
    return new Promise(function (resolve, reject) {
        if(promises.length > 0){
            for(let i = 0; i<promises.length; i++){
                promises[i].then(function (value) {
                    resolve(value);
                }, function (value) {
                    reject(value);
                })
            }
        }
    })
}

module.exports = Promise;

Generator

  • Generator可以暫停函數(shù)執(zhí)行,返回任意表達(dá)式的值词爬。
  • Generator函數(shù)有兩個(gè)特征秃嗜,一是,function關(guān)鍵字和函數(shù)名之間有個(gè)*號(hào)缸夹,二是痪寻,函數(shù)體內(nèi)部使用yield表達(dá)式。
  • 調(diào)用Generator并不執(zhí)行虽惭,返回的是遍歷器對(duì)象(Iterator)橡类。調(diào)用Iterator的next方法后,函數(shù)內(nèi)部指針從函數(shù)頭部或者上一次停下來(lái)的地方開(kāi)始執(zhí)行芽唇,直到遇到下一個(gè)yield表達(dá)式顾画。
  • 遇到y(tǒng)ield表達(dá)式,next函數(shù)返回一個(gè)對(duì)象形如{value: , done: false|true}形式匆笤,表達(dá)式的value值是yield后面的表達(dá)式值或者最后的return值研侣,如果沒(méi)有return,函數(shù)執(zhí)行完炮捧,value值就是undefined庶诡。yield表達(dá)式的返回值是next函數(shù)的傳入值或者undefined。
function* foo(x) {
  var y = 2 * (yield (x + 1));
  var z = yield (y / 3);
  return (x + y + z);
}

var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}

var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true }

for...of循環(huán)

for...of循環(huán)自動(dòng)遍歷Generator函數(shù)生成的Iterator對(duì)象咆课,不需要使用next()末誓。

另外扯俱,也可以使用拓展運(yùn)算符(...)、解構(gòu)賦值喇澡,Array.from方法內(nèi)部調(diào)用的迅栅,都是遍歷器接口。因此:

function* numbers () {
  yield 1
  yield 2
  return 3
  yield 4
}

// 擴(kuò)展運(yùn)算符
[...numbers()] // [1, 2]

// Array.from 方法
Array.from(numbers()) // [1, 2]

// 解構(gòu)賦值
let [x, y] = numbers();
x // 1
y // 2

// for...of 循環(huán)
for (let n of numbers()) {
  console.log(n)
}
// 1
// 2

async

  • async函數(shù)是Generator函數(shù)的語(yǔ)法糖晴玖。
  • async函數(shù)返回一個(gè)Promise對(duì)象

參考:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末读存,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子呕屎,更是在濱河造成了極大的恐慌让簿,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,835評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件榨惰,死亡現(xiàn)場(chǎng)離奇詭異拜英,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)琅催,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén)居凶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人藤抡,你說(shuō)我怎么就攤上這事侠碧。” “怎么了缠黍?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,481評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵弄兜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我瓷式,道長(zhǎng)替饿,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,303評(píng)論 1 282
  • 正文 為了忘掉前任贸典,我火速辦了婚禮视卢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘廊驼。我一直安慰自己据过,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,375評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布妒挎。 她就那樣靜靜地躺著绳锅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪酝掩。 梳的紋絲不亂的頭發(fā)上鳞芙,一...
    開(kāi)封第一講書(shū)人閱讀 49,729評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼积蜻。 笑死闯割,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的竿拆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,877評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼宾尚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼丙笋!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起煌贴,我...
    開(kāi)封第一講書(shū)人閱讀 37,633評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤御板,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后牛郑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體怠肋,經(jīng)...
    沈念sama閱讀 44,088評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,443評(píng)論 2 326
  • 正文 我和宋清朗相戀三年淹朋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了笙各。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,563評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡础芍,死狀恐怖杈抢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情仑性,我是刑警寧澤惶楼,帶...
    沈念sama閱讀 34,251評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站诊杆,受9級(jí)特大地震影響歼捐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晨汹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,827評(píng)論 3 312
  • 文/蒙蒙 一豹储、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宰缤,春花似錦颂翼、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,712評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至氧骤,卻和暖如春呻疹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背筹陵。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,943評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工刽锤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留镊尺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,240評(píng)論 2 360
  • 正文 我出身青樓并思,卻偏偏與公主長(zhǎng)得像庐氮,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子宋彼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,435評(píng)論 2 348

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

  • Promise的含義: ??Promise是異步編程的一種解決方案弄砍,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和...
    呼呼哥閱讀 2,166評(píng)論 0 16
  • 本文適用的讀者 本文寫(xiě)給有一定Promise使用經(jīng)驗(yàn)的人,如果你還沒(méi)有使用過(guò)Promise输涕,這篇文章可能不適合你音婶,...
    HZ充電大喵閱讀 7,299評(píng)論 6 19
  • 00衣式、前言Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大檐什。它由社區(qū)...
    夜幕小草閱讀 2,128評(píng)論 0 12
  • Promiese 簡(jiǎn)單說(shuō)就是一個(gè)容器碴卧,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果,語(yǔ)法上說(shuō)厢汹,Pr...
    雨飛飛雨閱讀 3,352評(píng)論 0 19
  • 上次讀書(shū)記這么多筆記并認(rèn)真梳理烫葬,還是在讀李笑來(lái)的《把時(shí)間當(dāng)作朋友》界弧。特別感謝成甲兄弟的這本書(shū)! 一邊讀一遍竊喜搭综,原...
    瑩瑩happygo閱讀 1,057評(píng)論 6 6