成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

js處理異步函數(shù):從callback到promise

dance / 2731人閱讀

摘要:在處理異步回調(diào)函數(shù)的情況有著越來(lái)越值得推崇的方法及類庫(kù),下面會(huì)依次介紹處理異步函數(shù)的發(fā)展史,及源碼解讀。而對(duì)象的狀態(tài),是由第一個(gè)的參數(shù)成功回調(diào)函數(shù)或失敗回調(diào)函數(shù)的返回值決定的。

函數(shù)的執(zhí)行分為同步和異步兩種。
同步即為 同步連續(xù)執(zhí)行,通俗點(diǎn)講就是做完一件事,再去做另一件事。
異步即為 先做一件事,中間可以去做其他事情,稍后再回來(lái)做第一件事情。
同時(shí)還要記住兩個(gè)特性:1.異步函數(shù)是沒(méi)有返回值的,return不管用哦 2.try{}catch(e){}不能捕獲異步函數(shù)中的異常。

js在處理異步回調(diào)函數(shù)的情況有著越來(lái)越值得推崇的方法及類庫(kù),下面會(huì)依次介紹js處理異步函數(shù)的發(fā)展史,及源碼解讀。
(本文代碼是運(yùn)行在node環(huán)境中)

1.callback
let fs = require("fs");
fs.readFile("./1.txt","utf8",function(err,data){
    console.log(data);
})

如果只有一個(gè)異步請(qǐng)求,那用callback還好,但是相信大多數(shù)前端開(kāi)發(fā)者都遇到過(guò)這兩種情況:
a.一個(gè)異步請(qǐng)求獲取到的結(jié)果是下一個(gè)異步請(qǐng)求的參數(shù)。(一直嵌套callback,代碼不好管理會(huì)形成回調(diào)地獄);

let fs = require("fs");
    fs.readFile("./1.txt","utf8",(err,data)=>{
        fs.readFile(data,"utf8",(err,data)=>{
            console.log(data);
        })
    })

b.發(fā)出兩個(gè)請(qǐng)求,只有當(dāng)兩個(gè)請(qǐng)求都成功獲取到數(shù)據(jù),在執(zhí)行下一步操作。

let fs =require("fs");
    fs.readFile("./1.txt","utf8",(err,data)=>{
        console.log(data);
    })
    fs.readFile("./2.txt","utf8",(err,data)=>{
        console.log(data);
    })

像類似這種情況,只有當(dāng)讀取到1.txt 和2.txt的文件的時(shí)候,我們同時(shí)獲取到兩個(gè)異步請(qǐng)求的結(jié)果。我們可以寫一個(gè)計(jì)數(shù)器的函數(shù),統(tǒng)一處理回調(diào);

function after(time,callback){
    let arr = [];
    return function(data){
        arr.push(data)
        if(--time==0){
            callback(arr);
        }
    }
}
  //統(tǒng)一處理回調(diào)結(jié)果的回調(diào)傳到after函數(shù)中。
  let out = after(2,(res)=>{console.log(res)});
  let fs =require("fs");
    fs.readFile("./1.txt","utf8",(err,data)=>{
        out(data);
    })
    fs.readFile("./2.txt","utf8",(err,data)=>{
        out(data);
    })

tips:

方便我們更好的了解計(jì)數(shù)器的實(shí)現(xiàn)原理,我們需要了解一個(gè)概念:高階函數(shù)
高階函數(shù):可以把函數(shù)作為參數(shù) 或者 return返回出一個(gè)函數(shù)。
舉個(gè)例子:

①.判斷一個(gè)變量是不是屬于一個(gè)類型:

function isType(type,content){
   return Object.protoType.toString.call(content) ==`[Object ${type}]`
}
let a = [1,2,3];
isType("Array", a) == true;

②.js數(shù)據(jù)類型有好多,我們每次調(diào)用都要傳入他的類型,麻不麻煩。所以我們寫一個(gè)方法,可以批量生成函數(shù)。

function isType(type){
    return function(content){
        return Object.protoType.toString.call(content) == `[Oject ${type}]`
    }
}
let isArray = isType("Array");
let a = [1,2,3]
isArray(a);

前兩種示例講的是return返回一個(gè)函數(shù),下面示例是一個(gè)預(yù)置函數(shù)及返回函數(shù)參數(shù)的結(jié)合示例(預(yù)置函數(shù))。

③.場(chǎng)景加入我有一個(gè)函數(shù),執(zhí)行第三次的時(shí)候我想輸出"我很可愛(ài)";平常我們可以這樣去實(shí)現(xiàn):

let time =0;
     function say(){
         if(++item==3){
         console.log("我很可愛(ài)")
         }
     }
     say();
     say();
     say();

高階函數(shù)實(shí)現(xiàn)的話:

 function after(time,callback){
        return function(){
            if(--time ==0){
                   callback();
            }
        }
     }
     function say(){
         console.log("我很可愛(ài)");
     }
     let out =after(3,say)
     out();
     out();
     out();

高階函數(shù)實(shí)現(xiàn)了將計(jì)時(shí)任務(wù)與業(yè)務(wù)邏輯拆分,高階函數(shù)的實(shí)現(xiàn)主要得益于作用域的查找。

2.Promise

在看完了上面的callback講述,主要其實(shí)還是講述了callback的弊端:
a.回調(diào)地獄(callback無(wú)法解決)
b.并發(fā)請(qǐng)求,同時(shí)拿到結(jié)果(可通過(guò)計(jì)數(shù)器方式,但是太費(fèi)勁,不太樂(lè)觀)
這個(gè)時(shí)候duang~duang~duang~,ES6帶著Promise來(lái)了~
Promise主要是es6提供的主要用于處理異步請(qǐng)求的一個(gè)對(duì)象,他能夠很好的解決回調(diào)地獄以及并發(fā)請(qǐng)求。
在寫promise源碼之前,我們先通過(guò)幾個(gè)調(diào)用promise的示例,了解一下promise的一些原理及特性,這在我們封裝promise的時(shí)候能夠起到很大的作用:
普通調(diào)用實(shí)例:

let fs = require("fs");
let p = new Promise(function(resolve,reject){
  fs.readFile("./1.txt","utf8",(err,data)=>{
      err?reject(err):resolve(data);
  })
})

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

1.promise實(shí)例可以多次調(diào)用then方法;

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

2.promise實(shí)例可以支持then方法的鏈?zhǔn)秸{(diào)用,jquery實(shí)現(xiàn)鏈?zhǔn)绞峭ㄟ^(guò)返回當(dāng)前的this。但是promise不可以通過(guò)返回this來(lái)實(shí)現(xiàn)。因?yàn)楹罄m(xù)通過(guò)鏈?zhǔn)皆黾拥膖hen不是通過(guò)原始的promise對(duì)象的狀態(tài)來(lái)決定走成功還是走失敗的。

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

3.只要then方法中的成功回調(diào)和失敗回調(diào),有返回值(包括undefiend),都會(huì)走到下個(gè)then方法中的成功回調(diào)中,并且把返回值作為下個(gè)then成功回調(diào)的參數(shù)傳進(jìn)去。

第一個(gè)then走成功:
p.then((data)=>{return undefined},(err)={console.log()}).then((data)=>{console.log(data)})
輸出:undefiend
第一個(gè)then走失?。?  p.then((data)=>{console.log(1)},(err)={return undefined).then((data)=>{console.log(data)})
輸出:undefiend

4.只要then方法中的成功回調(diào)和失敗回調(diào),有一個(gè)拋出異常,則都會(huì)走到下一個(gè)then中的失敗回調(diào)中;

第一個(gè)then走成功:
p.then((data)=>{throw new Err("錯(cuò)誤")},(err)={console.log(1)}).then((data)=>{console.log("成功")},(err)=>{console.log(err)})
輸出:錯(cuò)誤
第一個(gè)then走失?。?  p.then((data)=>{console.log(1)},(err)={throw new Err("錯(cuò)誤")).then((data)=>{console.log("成功")},(err)=>{console.log(err)})
輸出:錯(cuò)誤

5.成功和失敗 只能走一個(gè),如果成功了,就不會(huì)走失敗,如果失敗了,就不會(huì)走成功;

6.如果then方法中,返回的不是一個(gè)普通值,仍舊是一個(gè)promise對(duì)象,該如何處理?
答案:它會(huì)等待這個(gè)promise的執(zhí)行結(jié)果,并且傳給下一個(gè)then方法。如果成功,就把這個(gè)promise的結(jié)果傳給下一個(gè)then的成功回調(diào)并且執(zhí)行,如果失敗就把錯(cuò)誤傳給下一個(gè)then的失敗回調(diào)并且執(zhí)行。

7.具備catch捕獲錯(cuò)誤;如果catche前面的所有then方法都沒(méi)有失敗回調(diào),則catche會(huì)捕獲到錯(cuò)誤信息執(zhí)行他就是用來(lái)兜兒底用的。

p是一個(gè)失敗的回調(diào):
p.then((data)=>{console.log("成功")}).then((data)=>{成功}).catche(e){console.log("錯(cuò)誤")}

8.返回的結(jié)果和 promise是同一個(gè),永遠(yuǎn)不會(huì)成功和失敗

var  r  = new Promise(function(resolve,reject){
   return r;
})
r.then(function(){
    console.log(1)
},function(err){
    console.log(err)
})

以上是經(jīng)過(guò)調(diào)用es6提供的promise,發(fā)現(xiàn)的一些特性,下面我們會(huì)根據(jù)這些特性去封裝Promise類。

一.我們先通過(guò)初步了解的promise和簡(jiǎn)單的基本調(diào)用,簡(jiǎn)單的實(shí)現(xiàn)一個(gè)promise;

1.Promise支持傳入一個(gè)參數(shù),函數(shù)類型,這個(gè)函數(shù)往往是我們自己發(fā)起異步請(qǐng)求的函數(shù),我們稱它為執(zhí)行器actuator,這個(gè)函數(shù)會(huì)在調(diào)用new Promise()的作用域內(nèi)立即執(zhí)行,并且傳入兩個(gè)函數(shù)一個(gè)resolve另一個(gè)是reject作為參數(shù);

2.promise對(duì)象支持.then()的方法,then方法支持兩個(gè)參數(shù)一個(gè)為onFulfilled成功回調(diào)另一個(gè)為onRejected失敗回調(diào);onFulfilled接受參數(shù)data為異步請(qǐng)求拿到的數(shù)據(jù),onRejected接受的參數(shù)為捕獲到的異常錯(cuò)誤。

3.當(dāng)異步回調(diào)成功時(shí),執(zhí)行resolve,并且把回調(diào)結(jié)果傳給resolve函數(shù)。失敗則執(zhí)行reject,把異常信息傳給reject函數(shù)。(這一步往往是在actuator執(zhí)行器函數(shù)中我們自己去控制執(zhí)行的)

4.一個(gè)promise對(duì)象,執(zhí)行了resolve,就不會(huì)在去執(zhí)行reject。執(zhí)行了reject,也不會(huì)在去執(zhí)行resolve;
所以promise內(nèi)部中有一個(gè)類似狀態(tài)機(jī)的機(jī)制,它分為三種狀態(tài),創(chuàng)建一個(gè)promise對(duì)象,默認(rèn)狀態(tài)為"pending"狀態(tài),當(dāng)執(zhí)行了resolve,則該狀態(tài)變?yōu)?fulfilled",若果執(zhí)行了reject則該狀態(tài)變?yōu)?rejected",所以我們?cè)趖hen方法中需要根據(jù)狀態(tài)作出判斷;

5.promise對(duì)象已經(jīng)是成功狀態(tài)或是失敗狀態(tài)時(shí),都可以繼續(xù)通過(guò)then傳入函數(shù),會(huì)通過(guò)當(dāng)前的狀態(tài),來(lái)決定執(zhí)行成功還失敗,并且把結(jié)果或是錯(cuò)誤傳給相應(yīng)的函數(shù)。所以我們需要拿到的結(jié)果和捕獲的錯(cuò)誤。

    function Promise(fn){
    this.status = "pending";//狀態(tài)機(jī)
    //一個(gè)promise支持執(zhí)行多個(gè)then,所以需要一個(gè)池子把他的回調(diào)函數(shù)存儲(chǔ)起來(lái),統(tǒng)一遍歷執(zhí)行;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks =[]; 
    //保存結(jié)果或者錯(cuò)誤異常
    this.result = "";//當(dāng)前promise回調(diào)成功獲取到的數(shù)據(jù);
    this.reason = "";//當(dāng)前promise失敗的原因
    var self = this;
    function resolve(data){
        //執(zhí)行了reject就不能執(zhí)行resolve,所以必須保證是pending狀態(tài);
        //當(dāng)執(zhí)行回調(diào)成功,在執(zhí)行器調(diào)用resolve,我們?nèi)ケ闅v成功回調(diào)的池子,依次執(zhí)行;
        //保存結(jié)果,并且將當(dāng)前狀態(tài)設(shè)置為"fulfilled"
        if(self.status=="pending"){
            self.result = data;
            self.status = "fulfilled";
            self.onFulfilledCallbacks.forEach((fn)=>{
                fn(data);
            })
        }
          
    }
    function reject(err){
        //執(zhí)行了resolve就不能執(zhí)行reject,所以必須保證是pending狀態(tài);
        //當(dāng)執(zhí)行回調(diào)失敗,在執(zhí)行器調(diào)用reject,我們?nèi)ケ闅v成功回調(diào)的池子,依次執(zhí)行;
        //保存錯(cuò)誤原因并且將當(dāng)前狀態(tài)設(shè)置為"rejected"
        if(self.status=="pending"){
          self.reason= err;
          self.status ="rejected";
          self.onRejectedCallbacks.forEach((fn)=>{
              fn(err);
          })
        }
    }
    fn(resolve,reject)
}
Promise.prototype.then= function(onFulfilled,onRejected){
   //如果當(dāng)前promise對(duì)象成功狀態(tài),則直接執(zhí)行onFulfilled回調(diào)函數(shù),并且把拿到的已經(jīng)保存的成功數(shù)據(jù)傳進(jìn)去。
   if(this.status =="fulfilled"){
       onFulfilled(this.result)    
   }
   //如果當(dāng)前promise對(duì)象失敗狀態(tài),則直接執(zhí)行rejected回調(diào)函數(shù),并且把已經(jīng)保存的補(bǔ)貨失敗的原因傳進(jìn)去。
   if(this.status =="rejected"){
       onRejected(this.reason);
   }
   if(this.status == "pending"){
       this.onFulfilledCallbacks.push(onFulfilled);
       this.onRejectedCallbacks.push(onRejected);
   }
}

到目前為止我們已經(jīng)封裝了一個(gè)簡(jiǎn)易版的promise了,我們可以通過(guò)一些case去測(cè)試一下,是否滿足上面所描述的特性。

let fs = require("fs");
let p = new Promise((resolve,reject)=>{
   fs.readFile("./1.txt","utf8",function (err,data) {
              err ? reject(err):resolve(data);
   })
});
p.then(data=>{console.log(data)},err=>{console.log(err)}); 
p.then(data=>{console.log(data)},err=>{console.log(err)});

二、我們簡(jiǎn)易版的promise類,已經(jīng)初步實(shí)現(xiàn)了一些promise的基本特性;這一節(jié)我們我們簡(jiǎn)易版的promise進(jìn)行改版,把promise的更復(fù)雜的功能增加進(jìn)去。

1.當(dāng)我們調(diào)用promise時(shí),傳入的執(zhí)行器會(huì)立刻執(zhí)行,執(zhí)行器函數(shù)內(nèi)部是一個(gè)同步的過(guò)程,我們可以用try...catch捕獲錯(cuò)誤,并且應(yīng)該直接調(diào)用失敗的函數(shù)。

2.promise支持鏈?zhǔn)綄懛ǎ瑃hen后面繼續(xù).then ,原理并不是像jquery一樣返回一個(gè)this;而是不管當(dāng)前promise狀態(tài)是什么,都返回一個(gè)新的promise對(duì)象,官方文檔命名這個(gè)新的promise對(duì)象為promise2。
3.鏈?zhǔn)綄懛ㄖ械诙€(gè)then中的回調(diào)走成功還是走失敗,取決于上一個(gè)then中返回的promise(就是promise2)對(duì)象的狀態(tài)。 而 promise2對(duì)象的狀態(tài),是由第一個(gè)then的參數(shù)(成功回調(diào)函數(shù)或失敗回調(diào)函數(shù))的返回值決定的。如果返回的是一個(gè)值(包括返回的是undefined、""),則第二個(gè)then走成功;如果返回的仍舊是一個(gè)promise對(duì)象,那么promise2會(huì)等待返回的這個(gè)promise對(duì)象的回調(diào)結(jié)果而確定promise2的狀態(tài)值,如果回調(diào)結(jié)果拿到的是一個(gè)值(成功),那么promise2會(huì)將此值作為參數(shù)傳入字節(jié)的reosolve中并執(zhí)行,如果回調(diào)中拋出異常(失?。?,那么promise2會(huì)把異常傳到reject中并且執(zhí)行;

function Promise(fn){
    this.status = "pending";
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks =[]; 
    this.result = "";
    this.reason = "";
    var self = this;
    function resolve(data){
        if(self.status=="pending"){
            self.result = data;
            self.status = "fulfilled";
            self.onFulfilledCallbacks.forEach((fn)=>{
                fn(data);
            })
        }
          
    }
    function reject(err){           
        if(self.status=="pending"){
          self.reason= err;
          self.status ="rejected";
          self.onRejectedCallbacks.forEach((fn)=>{
              fn(err);
          })
        }
    }
    try{
        fn(resolve,reject)
    }catch(e){
        reject(e)
    }
    
}
Promise.prototype.then= function(onFulfilled,onRejected){
   //then方法什么都不傳,也可以支持連續(xù)調(diào)用  
   onFulfilled = onFulfilled ?onFulfilled :function(data){ return data};
   onRejected =onFulfilled ? onFulfilled :function(err){throw new Error(err)}
   let self = this;
   let Promise2;//聲明primise2
   if(this.status =="fulfilled"){
       Promise2 = new Promise(function(resolve,reject){
           //promise2的狀態(tài),決定下一個(gè)then方法中執(zhí)行成功還是失敗。
           //promise2的狀態(tài),是由第一個(gè)then的onFulfilled的返回值決定的。
           //當(dāng)我們執(zhí)行onFulfilled(我們通過(guò)then方法傳進(jìn)來(lái)的自己的函數(shù))的時(shí)候,是同步操作,需要通過(guò)trycatch捕獲異常,如果發(fā)現(xiàn)異常就直接走下一個(gè)then的reject失敗回調(diào)。
           //promise官方文檔規(guī)定,每一個(gè)resolve或是reject回調(diào)的執(zhí)行必須保證是在異步中執(zhí)行,所以我們強(qiáng)制加定時(shí)器,保證onFulfilled是異步執(zhí)行的。
           setTimeOut(function(){
               try{
                   let x = onFulfilled(self.result);
                   //獲取到返回值,需要去解析,從而判斷出promise2應(yīng)該走失敗還是成功。    
                   resolvePromise(Promise2,x,resolve,reject)                                              
               }catch(e){
                  //執(zhí)行reject,下一個(gè)then就會(huì)走失敗
                   reject(e);
               }
           })                                                      
       })          
   }
   if(this.status =="rejected"){
     Promise2 = new Promise(function(resolve,reject){
       setTimeout(function(){
           try{
               let x = onRejected(self.reason);
               resolvePromise(Promise2,x,resolve,reject)
           }catch(e){
               reject(e)
           }
       })
     })
       
   }
   if(this.status == "pending"){
   Promise2 = new Promise(function(resolve,reject){
        self.onFulfilledCallbacks.push(function(){
            setTimeout(function(){
                try{
                    let x =  onFulfilled(self.result);
                    resolvePromise(Promise2,x,resolve,reject);
                }catch (e){
                    reject(e)
                }
            })

        });
        self.onRejectedCallbacks.push(function(){
            setTimeout(function(){
                try {
                    let x =  onRejected(self.reason);
                    resolvePromise(Promise2,x,resolve,reject)
                }catch (e){
                    reject(e);
                }
            })

        });
    })
   }
   return Promise2;
}

function resolvePromise(promise2,x,resolve,reject){
    //此處如果相等會(huì)爆出類型錯(cuò)誤;
    if(promise2 == x){
        reject(new TypeError("循環(huán)引用了"))
    }
    //如果x是對(duì)象或函數(shù)(引用類型的值),則需要進(jìn)一步判斷。(這塊兒要想的多一些,因?yàn)閤是開(kāi)發(fā)人員寫的函數(shù)返回的,第一個(gè)then中回調(diào)返回的)
    //若果x是一個(gè)普通值,則直接執(zhí)行resolve,并且傳給下個(gè)then的成功; 
    //如果返回的是一個(gè)promise對(duì)象,則promise2則會(huì)等待返回的promise對(duì)象執(zhí)行完成,如果執(zhí)行完成后,看這個(gè)promise走的成功還是失敗,如果失敗則拋出異常。如果成功則將獲取的數(shù)據(jù)作為onFulfilled返回的結(jié)果,用于判斷promise2走成功或者失敗,因?yàn)榉祷氐慕Y(jié)果可能還是promise對(duì)象,所以用遞歸去執(zhí)行,知道拿到數(shù)據(jù)或者異常。(遞歸)
    //判斷是不是promise對(duì)象,通過(guò)有沒(méi)有then方法
    //捕獲異常是因?yàn)榕袛嗖粐?yán)謹(jǐn),存在then方法,可能也不是promise對(duì)象,調(diào)用它的then可能會(huì)報(bào)錯(cuò)。      
    let called =false;
    if(x!==null &&(typeof x =="object"|| typeof x =="function")){        
           try{
               let then =x.then;
               if(typeof then =="function"){
                   //promise對(duì)象
                   then.call(x,function(y){
                       if(called)return;
                       called = true;
                       resolvePromise(promise2,y,resolve,reject)
                   },function(err){
                       if(called)return;
                       called = true;
                       reject(err)
                   })
               
               }else{
                   //普通對(duì)象
                   resolve(x)
               }
           }catch(e){
              if(called)return;
              called = true;
              reject(e)
           }
    }else{
        resolve(x);
    }    
}

 到此,Promise的大部分特性都已經(jīng)具備了。但是Promise對(duì)象還有一些其他的方法,可供調(diào)用,比如說(shuō)catch方法,還有他的私有屬性all 、race、defferd,如果前面的Promise封裝懂了,那這些方法就so easy了,下面會(huì)根據(jù)這些方法的功能一一進(jìn)行封裝,
 

1.all方法處理 并發(fā)請(qǐng)求,同時(shí)獲得結(jié)果。一個(gè)失敗,則失敗,都成功,才算成功.這個(gè)時(shí)候我們就想到前面我們寫的計(jì)數(shù)器的用法。

 Promise.all([read("./1.txt"),read("./2.txt")]).then(res=>{console.log(res)})
 
 Promise.all = function(promiseArray){               
       return new Promise(function(resolve,reject){
           var result = [];
           var i=0;
           function processData(index,res){
               result[index] = res;
               if(++i==promiseArray.length){
                   resolve(result)
               } 
           }
           promiseArray.forEach((item,index)=>{
               item.then(res=>{processData(index,res)},reject)
           })
       })        
 };

2.race方法,Pomise.race,顧名思義“賽拍”,傳入多個(gè)異步promise,只要有一個(gè)成功,則就成功,有一個(gè)失敗則失敗,后面也可跟then方法。

Promise.race = function(promiseArray){
    return new Promise(function(resolve,reject){
        promiseArray.forEach((item,index)=>{
            item.then(resolve,reject);
        })
    })
}
Promise.race([read("./1.txt"),read("./5.txt")]).then(res=>{console.log(res)},err=>{console.log(err)})

3.生成一個(gè)成功的promise,把傳入的參數(shù),傳入到then的成功回調(diào)中,該方法返回一個(gè)promise

Promise.resolve=function(value){
    return new Promise(function(resolve,reject){
        //promise規(guī)范 resolve和reject函數(shù)必須是在異步回調(diào)中執(zhí)行
        setTimeout(function(){
            resolve(value);
        })
    })
}
Promise.resolve("123").then(res=>{console.log(res)})

4.生成一個(gè)失敗的promise,把傳入的參數(shù),傳入到then的失敗回調(diào)中。該方法返回一個(gè)promise

Promise.reject = function(err){
    return new Promise(function(resolve,reject){
        setTimeout(function(){
            reject(err);
        })

    })
}
Promise.reject("error").then(res=>{console.log(res)},err=>{console.log(err)})

5.catch托底捕獲錯(cuò)誤,這個(gè)方法是實(shí)例的共有方法,應(yīng)該放到Promise的原型上,每一個(gè) promise實(shí)例都可以調(diào)用.它支持一個(gè)參數(shù),該參數(shù)是之前所有的then中,并沒(méi)有失敗回調(diào),當(dāng)發(fā) 生錯(cuò)誤時(shí),最后統(tǒng)一在catch中進(jìn)行捕獲

Promise.prototype.catch = function(calllback){
return this.then(null,callback)
}

6.很多人都用過(guò)jquery的deferrd對(duì)象,他和promise的deffer對(duì)象很類似。promise的deferred對(duì)象只是對(duì)promise進(jìn)行了一次封裝

Promise.defer = Promise.deferred=function(){
    var obj = {};
    obj.promise = new Promise(function(resolve,reject){
        obj.resolve = resolve;
        obj.reject = reject;
    })
    return obj;
}
    let fs = require("fs");
 function read2 (url){
    var deferr = Promise.deferred();
    fs.readFile("./1.txt","utf8",(err,res)=>{
        err?deferr.reject(err):deferr.resolve(res);
    })
     return deferr;
}
read2("./1.txt").then(data=>{console.log(data)})

至此,一個(gè)完整的Promise.js封裝完成,當(dāng)然最后是需要模塊化導(dǎo)出的,我們采用CommonJS規(guī)范導(dǎo)出一個(gè)模塊 采用

module.exports = Promise;

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/93554.html

相關(guān)文章

  • 我了解的JavaScript異步編程

    摘要:接下來(lái)我們看下三類異步編程的實(shí)現(xiàn)。事件監(jiān)聽(tīng)事件發(fā)布訂閱事件監(jiān)聽(tīng)是一種非常常見(jiàn)的異步編程模式,它是一種典型的邏輯分離方式,對(duì)代碼解耦很有用處。 一、 一道面試題 前段時(shí)間面試,考察比較多的是js異步編程方面的相關(guān)知識(shí)點(diǎn),如今,正好輪到自己分享技術(shù),所以想把js異步編程學(xué)習(xí)下,做個(gè)總結(jié)。下面這個(gè)demo 概括了大多數(shù)面試過(guò)程中遇到的問(wèn)題: for(var i = 0; i < 3; i++...

    RichardXG 評(píng)論0 收藏0
  • JS引擎:它們是如何工作的?調(diào)用堆棧Promise,需要知道的所有內(nèi)容

    摘要:最受歡迎的引擎是,由和使用,用于,以及使用的。引擎它們是如何工作的全局執(zhí)行上下文和調(diào)用堆棧剛剛了解了引擎如何讀取變量和函數(shù)聲明,它們最終被放入了全局內(nèi)存堆中。事件循環(huán)只有一個(gè)任務(wù)它檢查調(diào)用堆棧是否為空。 為了保證可讀性,本文采用意譯而非直譯。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你! 有沒(méi)有想過(guò)瀏覽器如何讀取和運(yùn)行JS代碼? 這看起來(lái)很神奇,我們可以通過(guò)瀏覽...

    lavnFan 評(píng)論0 收藏0
  • JavaScript工作原理(四):事件循環(huán),異步編程的興起以及5招async/await實(shí)踐

    摘要:事件循環(huán)從回調(diào)隊(duì)列中獲取并將其推送到調(diào)用堆棧。如何工作請(qǐng)注意,不會(huì)自動(dòng)將您的回調(diào)函數(shù)放到事件循環(huán)隊(duì)列中。它設(shè)置了一個(gè)計(jì)時(shí)器,當(dāng)計(jì)時(shí)器到期時(shí),環(huán)境將您的回調(diào)函數(shù)放入事件循環(huán)中,以便將來(lái)的某個(gè)事件會(huì)將其選中并執(zhí)行它。 我們將通過(guò)回顧第一篇文章中單線程編程的缺點(diǎn),然后在討論如何克服它們來(lái)構(gòu)建令人驚嘆的JavaScript UI。在文章結(jié)尾處,我們將分享5個(gè)關(guān)于如何使用async / awai...

    piglei 評(píng)論0 收藏0
  • JS 異步(callbackPromise→async/await)

    摘要:異步編程三座大山原型原型鏈作用域閉包同步異步。異步操作執(zhí)行完畢后,再執(zhí)行該回調(diào)函數(shù),確?;卣{(diào)在異步操作之后執(zhí)行?;卣{(diào)函數(shù)本身是我們約定俗成的一種叫法,我們定義它,但是并不會(huì)自己去執(zhí)行它,它最終被其他人執(zhí)行了。 JS異步編程 JS三座大山:原型原型鏈、作用域閉包、同步異步。之前有寫過(guò)自己對(duì)閉包的理解,今天來(lái)總結(jié)一下JS中的異步。 思考(案例來(lái)自stackoverflow): functi...

    gougoujiang 評(píng)論0 收藏0
  • 《Node.js設(shè)計(jì)模式》基于ES2015+的回調(diào)控制流

    摘要:以下展示它是如何工作的函數(shù)使用構(gòu)造函數(shù)創(chuàng)建一個(gè)新的對(duì)象,并立即將其返回給調(diào)用者。在傳遞給構(gòu)造函數(shù)的函數(shù)中,我們確保傳遞給,這是一個(gè)特殊的回調(diào)函數(shù)。 本系列文章為《Node.js Design Patterns Second Edition》的原文翻譯和讀書(shū)筆記,在GitHub連載更新,同步翻譯版鏈接。 歡迎關(guān)注我的專欄,之后的博文將在專欄同步: Encounter的掘金專欄 知乎專欄...

    LiuRhoRamen 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<