Promise對象原理解析

Promise對象原理解析

ES6 原生提供了 Promise 對象。
所謂 Promise,就是一個對象,用來傳遞異步操作的消息。它代表了某個未來才會知道結果的事件(通常是一個異步操作)晒屎,并且這個事件提供統(tǒng)一的 API,可供進一步處理缓升。

異步方法的各種調用形式

以ajax請求為例

  • ES5正常寫法

這種寫法缺點如果在回調中還有需要執(zhí)行的異步方法鼓鲁,容易進入套娃模式。

$.get(url,(res)=>{
    //此處執(zhí)行請求成功的回調
  $.get(url2,(res2)=>{
    //此處執(zhí)行請求成功的回調2
    ...
    ...
    
  })
})
  • Promise寫法
getAjax(url).then((res)=>{
    //此處執(zhí)行請求成功的回調
})
  • async_await 寫法
(async ()=>{ 
   //await等待異步方法的執(zhí)行仔沿,執(zhí)行成功將響應結果返回
    let res = await getAjax(url)
   
})()

總結:

  • ES5寫法和promise寫法坐桩,主要區(qū)別在寫法的不同,可以讓回調函數(shù)封锉,劃分出去在.then的函數(shù)里去執(zhí)行绵跷,使得代碼更加的易讀,也可以將兩個不同的參數(shù)成福,劃分開來寫碾局。
  • async_await和promise的區(qū)別,async_await只是promise實現(xiàn)的語法糖而已奴艾,這種形式的寫法在底層編譯之后會自動轉化成promise的寫法

Promise實現(xiàn)原理(自已實現(xiàn)MyPromise對象)

創(chuàng)建類構造對象

class MyPromise{
    constructor(fn) {
        //將成功的事件函數(shù)集成在successList數(shù)組里
        this.successList  = [];
        //這里將所有的失敗函數(shù)集成到failList里
        this.failList = []
        //pending,fullfilled,rejected
        this.state = "pending"
        //傳入的函數(shù)對象,(異步操作的函數(shù)內容)
        fn(this.resolveFn.bind(this),this.rejectFn.bind(this))
    }
}

構造函數(shù)的作用:

  • 聲明成功函數(shù)放置的數(shù)組對象
  • 聲明失敗函數(shù)放置的數(shù)組對象
  • 定義初始化狀態(tài)
  • 調用傳入進行執(zhí)行異步內容的函數(shù)(在未來有成功的結果時調用傳入進去的成功函數(shù)净当,在未來失敗時調用傳入進行的失敗函數(shù))

在MyPromise對象中定義 接收“成功或者失敗”時需要調用的函數(shù)

將“成功或者失敗函數(shù)”存放到成功函數(shù)隊列和失敗函數(shù)隊列中,以便在事件完成時調用蕴潦。

class MyPromise{
    constructor(fn) {
        //將成功的事件函數(shù)集成在successList數(shù)組里
        this.successList  = [];
        //這里將所有的失敗函數(shù)集成到failList里
        this.failList = []
        //pending,fullfilled,rejected
        this.state = "pending"
        //傳入的函數(shù)對象,(異步操作的函數(shù)內容)
        fn(this.resolveFn.bind(this),this.rejectFn.bind(this))
    }
  
    //then方法接收成功或者失敗時需要調用的函數(shù)像啼,將函數(shù)存放到成功或失敗函數(shù)隊列中
    then(successFn,failFn){
        if(typeof successFn=='function'){
            this.successList.push(successFn)
        }
        if(typeof failFn=='function'){
            this.failList.push(failFn)
        }
    }
    //catch方法接收失敗時需要調用的函數(shù),將函數(shù)存放到失敗函數(shù)隊列中
    catch(failFn){
        if(typeof failFn=='function'){
            this.failList.push(failFn)
        }
    }
}

作用:

  • 接收成功和失敗的函數(shù)放到成功和失敗的函數(shù)隊列里

定義 在事件完成時 調用成功函數(shù)和失敗函數(shù)的 函數(shù)(有點繞)

class MyPromise{
    constructor(fn) {
        //將成功的事件函數(shù)集成在successList數(shù)組里
        this.successList  = [];
        //這里將所有的失敗函數(shù)集成到failList里
        this.failList = []
        //pending,fullfilled,rejected
        this.state = "pending"
        //傳入的函數(shù)對象,(異步操作的函數(shù)內容)
        fn(this.resolveFn.bind(this),this.rejectFn.bind(this))
    }
  
    //then方法接收成功或者失敗時需要調用的函數(shù)潭苞,將函數(shù)存放到成功或失敗函數(shù)隊列中
    then(successFn,failFn){
        if(typeof successFn=='function'){
            this.successList.push(successFn)
        }
        if(typeof failFn=='function'){
            this.failList.push(failFn)
        }
    }
    //catch方法接收失敗時需要調用的函數(shù)忽冻,將函數(shù)存放到失敗函數(shù)隊列中
    catch(failFn){
        if(typeof failFn=='function'){
            this.failList.push(failFn)
        }
    }
    
    //當事件成功時,執(zhí)行此函數(shù)此疹,此函數(shù)會執(zhí)行成功函數(shù)隊列中的所有函數(shù)
    resolveFn(res){
        this.state = "fullfilled"
       //循環(huán)調用成功函數(shù)隊列中的函數(shù)
        this.successList.forEach(function(item,index){
            //將成功的事件循環(huán)調用
            item(res)
        })
    }
  
  //當事件失敗時僧诚,執(zhí)行此函數(shù)遮婶,此函數(shù)會執(zhí)行失敗函數(shù)隊列中的所有函數(shù)
    rejectFn(res){
        this.state = 'rejected'
        //循環(huán)調用失敗函數(shù)隊列中的函數(shù)
        this.failList.forEach(function(item,index){
            item(res)
        })
        
        throw Error(res);
    }
}

作用:

  • 成功時調用成功數(shù)組里所有的函數(shù),失敗時調用失敗數(shù)組里所有的函數(shù)湖笨。

應用MyPromise對象

以node中fs模塊為例旗扑,我們使用MyPromise對象封裝一個fs讀取文件的方法

引入fs

let fs = require('fs');

封裝fsRead方法,讀取文件

//例:使用MyPromise對象封裝一個fs模塊方法
function fsRead(path){
    return new MyPromise(function(resolve,reject){
        fs.readFile(path,{flag:'r',encoding:"utf-8"},function(err,data){
            if(err){
                reject(err)
            }else{
                resolve(data)
            }
        })
    })
}

準備需要讀取的文件test.txt

小池
作者:楊萬里
泉眼無聲惜細流慈省,樹陰照水愛晴柔臀防。
小荷才露尖尖角,早有蜻蜓立上頭边败。

調用fsRead方法讀取test.txt文件

(async ()=>{

    //需要讀取的文件路徑
    let path = './test.txt';

    //調用我們使用MyPromise對象封裝的fsRead方法異步方法
    //Promise寫法
    fsRead(path).then((data)=>{
        console.log("===========Promise寫法=============")
        console.log(data)
    })

        //async_await寫法
    let data = await fsRead(path)
    console.log("===========async_await寫法=============")
    console.log(data)
})()

執(zhí)行 node node .\mypromise.js控制臺輸入

PS E:\Workspace_VSCode\node-in-action> node .\promise.js
===========Promise寫法=============
小池
作者:楊萬里
泉眼無聲惜細流清钥,樹陰照水愛晴柔。
小荷才露尖尖角放闺,早有蜻蜓立上頭。
===========async_await寫法=============
小池
作者:楊萬里
泉眼無聲惜細流缕坎,樹陰照水愛晴柔怖侦。
小荷才露尖尖角,早有蜻蜓立上頭谜叹。

完整代碼

let fs = require('fs');

class MyPromise{
    constructor(fn) {
        //將成功的事件函數(shù)集成在successList數(shù)組里
        this.successList  = [];
        //這里將所有的失敗函數(shù)集成到failList里
        this.failList = []
        //pending,fullfilled,rejected
        this.state = "pending"
        //傳入的函數(shù)對象,(異步操作的函數(shù)內容)
        fn(this.resolveFn.bind(this),this.rejectFn.bind(this))
    }
    then(successFn,failFn){
        if(typeof successFn=='function'){
            this.successList.push(successFn)
        }
        if(typeof failFn=='function'){
            this.failList.push(failFn)
        }
    }
    catch(failFn){
        if(typeof failFn=='function'){
            this.failList.push(failFn)
        }
    }
    resolveFn(res){
        this.state = "fullfilled"
        this.successList.forEach(function(item,index){
            //將成功的事件循環(huán)調用
            item(res)
        })
    }
    rejectFn(res){
        this.state = 'rejected'
        //注冊到的失敗所有事件進行調用
        this.failList.forEach(function(item,index){
            item(res)
        })
        
        throw Error(res);
    }
}


//例:使用MyPromise對象封裝一個fs模塊方法
function fsRead(path){
    return new MyPromise(function(resolve,reject){
        fs.readFile(path,{flag:'r',encoding:"utf-8"},function(err,data){
            if(err){
                reject(err)
            }else{
                resolve(data)
            }
        })
    })
}


(async ()=>{

    //需要讀取的文件路徑
    let path = './test.txt';

    //調用我們使用MyPromise對象封裝的fsRead方法異步方法
    //Promise寫法
    fsRead(path).then((data)=>{
        console.log("===========Promise寫法=============")
        console.log(data)
    })


    let data = await fsRead(path)
    console.log("===========async_await寫法=============")
    console.log(data)
})()


?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末匾寝,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子荷腊,更是在濱河造成了極大的恐慌艳悔,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件女仰,死亡現(xiàn)場離奇詭異猜年,居然都是意外死亡,警方通過查閱死者的電腦和手機疾忍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門乔外,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人一罩,你說我怎么就攤上這事杨幼。” “怎么了聂渊?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵差购,是天一觀的道長。 經常有香客問我汉嗽,道長欲逃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任诊胞,我火速辦了婚禮暖夭,結果婚禮上锹杈,老公的妹妹穿的比我還像新娘。我一直安慰自己迈着,他們只是感情好竭望,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著裕菠,像睡著了一般咬清。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上奴潘,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天旧烧,我揣著相機與錄音,去河邊找鬼画髓。 笑死掘剪,一個胖子當著我的面吹牛,可吹牛的內容都是我干的奈虾。 我是一名探鬼主播夺谁,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼肉微!你這毒婦竟也來了匾鸥?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤碉纳,失蹤者是張志新(化名)和其女友劉穎勿负,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體劳曹,經...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡奴愉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了铁孵。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躁劣。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖库菲,靈堂內的尸體忽然破棺而出账忘,到底是詐尸還是另有隱情,我是刑警寧澤熙宇,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布鳖擒,位于F島的核電站,受9級特大地震影響烫止,放射性物質發(fā)生泄漏蒋荚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一馆蠕、第九天 我趴在偏房一處隱蔽的房頂上張望期升。 院中可真熱鬧惊奇,春花似錦、人聲如沸播赁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽容为。三九已至乓序,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間坎背,已是汗流浹背替劈。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留得滤,地道東北人陨献。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像懂更,于是被迫代替她去往敵國和親湿故。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348