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

資訊專(zhuān)欄INFORMATION COLUMN

Promise詳解

ckllj / 1790人閱讀

摘要:等待十秒后代碼才算執(zhí)行完畢常見(jiàn)用法將定時(shí)器和異步操作放在一起,如果定時(shí)器先觸發(fā),則認(rèn)為超時(shí),告知用戶(hù)。

Promise
介紹:

用于異步計(jì)算

將異步操作隊(duì)列化,按照期望的順序執(zhí)行,返回符合預(yù)期的結(jié)果

可以在對(duì)象之間傳遞和操作promise,幫助我們處理隊(duì)列

由于promise是控制異步操作的,所以先來(lái)介紹一下在promise之前異步操作的常見(jiàn)語(yǔ)法。

事件偵聽(tīng)與響應(yīng)

回調(diào)函數(shù)(例如ajax請(qǐng)求回調(diào))

異步回調(diào)的問(wèn)題:

回調(diào)地獄問(wèn)題(一個(gè)回調(diào)嵌入一個(gè)回調(diào),特別是一些數(shù)據(jù)庫(kù)操作和文件操作 , 難以維護(hù))

無(wú)法正常使用 return 和 throw

異步回調(diào)的回調(diào)函數(shù)都是在一個(gè)新棧中,所以在現(xiàn)在的棧無(wú)法獲取到先前棧的信息。之前的棧也捕獲不到當(dāng)前棧拋出的錯(cuò)誤,所以在異步回調(diào)中無(wú)法正常使用try catch正常處理錯(cuò)誤。

在異步回調(diào)中經(jīng)常需要在外層回調(diào)中去定義一些變量給內(nèi)層回調(diào)使用。

talk is cheap , show me the code

const path = require("path");
const fs = require("fs");
//尋找最大文件的函數(shù)
function findLargest(dir,callback){
    fs.readdir(dir,function(err,files){
        if(err) return callback(err); //[錯(cuò)誤使用回調(diào)來(lái)處理]
            let count = files.length; //獲取文件長(zhǎng)度
            let errored = false; //是否錯(cuò)誤
            let stats = [];
            //遍歷文件夾下的所有文件
            files.forEach(file => {
                fs.stat(path.join(dir,file),(err,stat) =>{
                    if(errored) return;
                    if(err){
                        errored = true;
                        return callback(err);
                    }
                    stats.push(stat);
                    if(--count === 0){
                        let largest = stats
                        .filter(function(stat){
                            console.log("-----");
                            console.log(stat.isFile());
                            return stat.isFile();
                        }) //先判斷是否是文件
                        .reduce(function(prev,next){
                            //判斷大小
                            if(prev.size > next.size) { return prev; }
                            return next;
                        });
                    callback(null,files[stats.indexOf(largest)])
                }
            })
        })
    })
}

findLargest("../blog/blogDemo/移動(dòng)端滾動(dòng)詳解demo",function(err,filename){
    if(err) return console.error(err);
    console.log("largest file was:",filename);
})

上面就是一個(gè)查找最大文件的例子,其中有許多回調(diào)帶來(lái)的問(wèn)題。接下來(lái)我們先回歸主題,學(xué)習(xí)一些promise的使用,然后使用promise來(lái)改寫(xiě)這個(gè)例子。

promise詳解

new Promise(
    /*實(shí)例化Promise時(shí)傳入一個(gè)執(zhí)行器,也就是一個(gè)函數(shù)*/
    function(resolve,reject){
        //異步操作放在這里

        resolve(); //處理成功,修改實(shí)例化的promise對(duì)象的狀態(tài)為fulfilled
        reject(); //處理失敗,修改實(shí)例化的promise對(duì)象的狀態(tài)為rejected
    }
)
.then(function A(){
    //成功之后的處理,即調(diào)用resolve()就執(zhí)行A中的內(nèi)容
},function B(){
    //失敗之后的處理,即調(diào)用reject()或者拋出了錯(cuò)誤,就執(zhí)行B中的內(nèi)容
})

promise有三個(gè)狀態(tài):

pending 【待定】初始狀態(tài)
fulfilled 【實(shí)現(xiàn)】操作成功
rejected 【否決】操作失敗

promise的狀態(tài)一發(fā)生改變,立馬調(diào)用.then()中的響應(yīng)函數(shù)處理后續(xù)步驟,如果then()中返回了一個(gè)新的promise實(shí)例,則繼續(xù)循環(huán)下去。

promise常用的場(chǎng)景:

console.log("start");
new Promise(function(resolve,reject){
    setTimeout(function(){    //定時(shí)器模擬異步
        resolve("hello");    //修改promise狀態(tài)調(diào)用then中的第一個(gè)函數(shù)
    },2000);
}).then((value)=>{
    console.log(value);    //接收resolve傳來(lái)的值
    return new Promise(function(resolve){   //該then()返回一個(gè)新的promise實(shí)例,后面可以繼續(xù)接then
        setTimeout(function(){
            resolve("world");       //修改新promise的狀態(tài),去調(diào)用then
        },3000)
    })  
}).then((value)=>{
   console.log(value);
})

//輸出結(jié)果:
/*
    立即輸出   start
    兩秒輸出   hello
    再三秒     world
*/

上面我們?cè)?then() 函數(shù)中返回的是一個(gè)新的promise,如果返回的不是一個(gè)新的promise會(huì)怎樣呢?依然是上面的代碼,稍作修改。

console.log("start");
new Promise(function(resolve,reject){
    setTimeout(function(){  
        resolve("hello");    
    },2000);
}).then((value)=>{
    console.log(value);  
    (function(){
        return new Promise(function(resolve){   
            setTimeout(function(){
                resolve("world");       
            },3000)
        })  
    })();  
    return false; 
}).then((value)=>{
   console.log(value);
})
/*
    結(jié)果:
       立即輸出   start
       兩秒輸出   hello
       三秒輸出   flase
*/

根據(jù)上面的運(yùn)行結(jié)果來(lái)看,如果在一個(gè)then()中沒(méi)有返回一個(gè)新的promise,則return 什么下一個(gè)then就接受什么,在上面的實(shí)例代碼中return的是false,下一個(gè)then中接受到的value就是false,如果then中沒(méi)有return,則默認(rèn)return的是undefined.

注意:then中return Promise必須是在then函數(shù)的作用域中return,不能在其他函數(shù)作用域中return,無(wú)效。上面的例子中return Promise就是在一個(gè)立即執(zhí)行函數(shù)中返回的,所以無(wú)效。

.then()中包含.then()的嵌套情況
then()的嵌套會(huì)先將內(nèi)部的then()執(zhí)行完畢再繼續(xù)執(zhí)行外部的then();在多個(gè)then嵌套時(shí)建議將其展開(kāi),將then()放在同一級(jí),這樣代碼更清晰。

console.log("start");
new Promise((resolve,reject)=>{
    setTimeout(function(){
        console.log("step");
        resolve(110);
    },1000)
})
.then((value)=>{
    return new Promise((resolve,reject)=>{
        setTimeout(function(){
            console.log("step1");
            resolve(value);
        },1000)
    })
    .then((value)=>{
        console.log("step 1-1");
        return value;
    })
    .then((value)=>{
        console.log("step 1-2");
        return value;
    })
})
.then((value)=>{
    console.log(value);
    console.log("step 2");
})
/*
 start
 step
 step1
 step 1-1
 step 1-2
 110
 step 2
*/

//展開(kāi)之后的代碼
console.log("start");
new Promise((resolve,reject)=>{
    setTimeout(function(){
        console.log("step");
        resolve(110);
    },1000)
})
.then((value)=>{
    return new Promise((resolve,reject)=>{
        setTimeout(function(){
            console.log("step1");
            resolve(value);
        },1000)
    })
})
.then((value)=>{
        console.log("step 1-1");
        return value;
    })
.then((value)=>{
    console.log("step 1-2");
    return value;
})
.then((value)=>{
    console.log(value);
    console.log("step 2");
})

錯(cuò)誤處理
promise處理錯(cuò)誤有兩種方式,一種是發(fā)現(xiàn)錯(cuò)誤執(zhí)行then中的第二個(gè)回調(diào)函數(shù)來(lái)處理錯(cuò)誤,一種是.catch()來(lái)處理錯(cuò)誤

注意:拋出ERROR時(shí),只有在執(zhí)行函數(shù)的頂層拋出后面的catch才會(huì)接受到。這里如果在setTimeout中拋出錯(cuò)誤,catch和then中的錯(cuò)誤處理函數(shù)是接受不到的

//1.根據(jù)錯(cuò)誤執(zhí)行then中第二個(gè)回調(diào)來(lái)處理錯(cuò)誤
new Promise((resolve,reject)=>{
    setTimeout(function(){
        //只要出現(xiàn)了錯(cuò)誤或者調(diào)用了reject,就可以在then的第二個(gè)函數(shù)中獲取到
        reject("err");
    },1000)
}).then((value)=>{
    console.log(value);
},
//出錯(cuò)之后的執(zhí)行函數(shù)
(err)=>{
    console.log("出錯(cuò)了");
    console.log(err);
})
/*
    出錯(cuò)了
    err
*/

//2.根據(jù)catch來(lái)獲取錯(cuò)誤,拋出err或者執(zhí)行reject()都會(huì)在catch中獲取到錯(cuò)誤信息
new Promise((resolve,reject)=>{
    //只要出現(xiàn)了錯(cuò)誤,就可以在then的第二個(gè)函數(shù)中獲取到
    setTimeout(function(){
        reject("一個(gè)錯(cuò)誤");
    },1000)
}).then((value)=>{
    console.log(value);
}).catch(err=>{
    console.log("錯(cuò)誤信息:"+err);
})
/*
    錯(cuò)誤信息:一個(gè)錯(cuò)誤
*/

更推薦使用catch的方式進(jìn)行處理錯(cuò)誤,因?yàn)閏atch能獲取到之前所有then中出現(xiàn)的錯(cuò)誤

catch和then的連用
如果每一步都有可能出現(xiàn)錯(cuò)誤,那么就可能出現(xiàn)catch后面接上then的情況。上代碼

new Promise((resolve,reject)=>{
    resolve();
})
.then(value=>{
    console.log("done 1");
    throw new Error("done 1 error");
})
.catch(err=>{
    console.log("錯(cuò)誤信息1:"+err);
})
.then(value=>{
    console.log("done 2");
})
.catch(err=>{
    console.log("錯(cuò)誤信息2:"+err);
})
/*
 done 1
 錯(cuò)誤信息1:Error: done 1 error
 done 2

 說(shuō)明catch后面會(huì)繼續(xù)執(zhí)行then,catch返回的也是一個(gè)promise實(shí)例
*/
new Promise((resolve,reject)=>{
    resolve();
})
.then(value=>{
    console.log("done 1");
    throw new Error("done 1 error");
})
.catch(err=>{
    console.log("錯(cuò)誤信息1:"+err);
    throw new Error("catch error");
})
.then(value=>{
    console.log("done 2");
})
.catch(err=>{
    console.log("錯(cuò)誤信息2:"+err);
})
/*
 done 1
 錯(cuò)誤信息1:Error: done 1 error
 錯(cuò)誤信息2:Error: catch error

 如果在catch中也拋出了錯(cuò)誤,則后面的then的第一個(gè)函數(shù)不會(huì)執(zhí)行,因?yàn)榉祷氐膒romise狀態(tài)已經(jīng)為rejected了
*/

總的來(lái)說(shuō),catch之后可以接then,catch也是返回的一個(gè)promise對(duì)象。如果catch中出現(xiàn)錯(cuò)誤,則promise狀態(tài)修改成reject,否則為fullfilled狀態(tài)

Promise.all()
將多個(gè)Promise批量執(zhí)行,所有的Promise都完畢之后返回一個(gè)新的Promise。

接收一個(gè)數(shù)組作為參數(shù)

數(shù)組中可以是Promise實(shí)例,也可以是別的值,只有Promise會(huì)等待狀態(tài)的改變

所有子Promise完成,則該P(yáng)romise完成,并且返回值是參數(shù)數(shù)組中所有Promise實(shí)例的結(jié)果組成的數(shù)組

有任何一個(gè)Promise失敗,則該P(yáng)romise失敗,返回值是第一個(gè)失敗的Promise的結(jié)果

console.log("here we go");
Promise.all([1,2,3])
    .then(all=>{
        console.log("1: " + all); 
        return Promise.all([function(){
            console.log("ooxx");
        },"xxoo",false])
    })
    .then(all=>{
        console.log("2: " + all);
        let p1 = new Promise(resolve=>{
            setTimeout(function(){
                resolve("I"m p1");
            },1500)
        });
        let p2 = new Promise(resolve=>{
            setTimeout(function(){
                resolve("I"m p2");
            },2000)
        });
        return Promise.all([p1,p2]);
    })
    .then(all=>{
        console.log("3: "+all);
        let p1 = new Promise((resolve,reject)=>{
            setTimeout(function(){
                resolve("P1");
            },1000)
        })
        let p2 = new Promise((resolve,reject)=>{
            setTimeout(function(){
                reject("P2");
            },3000)
        })
        let p3 = new Promise((resolve,reject)=>{
            setTimeout(function(){
                reject("P3");
            },2000)
        })
        return Promise.all([p1,p2,p3]);
    })
    .then(all=>{
        console.log("all: " + all);
    })
    .catch(err=>{
        console.log("Catch:" + err);
    })
    /*
         here we go
         1: 1,2,3
         2: function(){
            console.log("ooxx");
            },xxoo,false
         3: I"m p1,I"m p2    
         Catch:P3      

         證明了上面的四點(diǎn)。
    */

Promise.race()
和Promise.all()差不多,區(qū)別就是傳入的數(shù)組中有一個(gè)Promise完成了則整個(gè)Promise完成了。

let p1 = new Promise(resolve=>{
    setTimeout(function(){
        resolve("p1");
    },10000);
})
let p2 = new Promise(resolve=>{
    setTimeout(function(){
        resolve("p2");
    },1000);
})
Promise.race([p1,p2])
.then((value)=>{
    console.log(value);
})
/*
    p1     1s之后輸出
    。。    等待十秒后代碼才算執(zhí)行完畢
*/

常見(jiàn)用法:

將定時(shí)器和異步操作放在一起,如果定時(shí)器先觸發(fā),則認(rèn)為超時(shí),告知用戶(hù)。

let p1 = new Promise(resolve=>{
    $.ajax({
        success:function(result){
            resolve(result);
        }
    }); //異步操作
})
let p2 = new Promise(resolve=>{
    setTimeout(function(){
        resolve("timeout");
    },10000);
})
Promise.race([p1,p2])
.then(value=>{
    if(value === "timeout"){
        alert("請(qǐng)求超時(shí)");
    }
})

將回調(diào)包裝為Promise
好處:1.可讀性好 2. 返回的結(jié)果可以放在任意Promise隊(duì)列

// 將nodejs中fs模塊的readDir和readFile方法包裝為Promise
//FileSystem.js
const fs = require("fs");
module.exports = {
    readDir: function(path,options){
        return new Promise(resolve=>{
            fs.readdir(path,options,(err,files)=>{
               if(err){
                   throw err;
               }
               resolve(files);
            })
        })
    },
    readFile: function(path,options){
        return new Promise(resolve=>{
            fs.readFile(path,options,(err,content)=>{
                if(err) throw err;
                resolve(content);
            })
        })
    }
}

//test.js
const fs = require("./FileSystem");
fs.readFile("./test.txt","utf-8")
    .then(content=>{
       console.log(content);
    })

尋找最大文件Promise改版

const fs = require("fs");
const path = require("path");
const FileSystem = require("./FileSystem"); //用上面封裝的FileSystem

function findLargest(dir) {

    return FileSystem
        .readDir(dir, "utf-8")
        .then(files => {
            return Promise.all(files.map(file=>{
                return new Promise(resolve =>{
                    fs.stat(path.join(dir,file),(err,stat)=>{
                        if err throw err;
                        if(stat.isDirectory()){
                            return resolve({
                                size: 0
                            });
                        }
                        stat.file = file;
                        resolve(stat);
                    });
                });
            }));
        })
        .then( stats =>{
            let biggest = stats.reduce((memo,stat)=>{
                if(memo.size < stat.size){
                    return stat;
                }
                return memo;
            });
            return biggest.file;
        })
}

我的文章都可以在我的gitbook上找到。歡迎star哈哈!gitbook地址

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

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

相關(guān)文章

  • async await詳解

    摘要:本身就是的語(yǔ)法糖。類(lèi)似于后面代碼會(huì)等內(nèi)部代碼全部完成后再執(zhí)行打印結(jié)果操作符用于等待一個(gè)對(duì)象。它只能在異步函數(shù)中使用。參考附在版本位中是可以直接使用的。持續(xù)更新中來(lái)點(diǎn)顆吧 async await本身就是promise + generator的語(yǔ)法糖。 本文主要講述以下內(nèi)容 async awiat 實(shí)質(zhì) async await 主要特性 async await 實(shí)質(zhì) 下面使用 pro...

    Shimmer 評(píng)論0 收藏0
  • async await詳解

    摘要:本身就是的語(yǔ)法糖。類(lèi)似于后面代碼會(huì)等內(nèi)部代碼全部完成后再執(zhí)行打印結(jié)果操作符用于等待一個(gè)對(duì)象。它只能在異步函數(shù)中使用。參考附在版本位中是可以直接使用的。持續(xù)更新中來(lái)點(diǎn)顆吧 async await本身就是promise + generator的語(yǔ)法糖。 本文主要講述以下內(nèi)容 async awiat 實(shí)質(zhì) async await 主要特性 async await 實(shí)質(zhì) 下面使用 pro...

    KavenFan 評(píng)論0 收藏0
  • async await詳解

    摘要:本身就是的語(yǔ)法糖。類(lèi)似于后面代碼會(huì)等內(nèi)部代碼全部完成后再執(zhí)行打印結(jié)果操作符用于等待一個(gè)對(duì)象。它只能在異步函數(shù)中使用。參考附在版本位中是可以直接使用的。持續(xù)更新中來(lái)點(diǎn)顆吧 async await本身就是promise + generator的語(yǔ)法糖。 本文主要講述以下內(nèi)容 async awiat 實(shí)質(zhì) async await 主要特性 async await 實(shí)質(zhì) 下面使用 pro...

    yedf 評(píng)論0 收藏0
  • Promise加載圖片用法詳解

    摘要:現(xiàn)在不會(huì)用都不好意思說(shuō)自己是前端,為什么火起來(lái),一句話解決了回調(diào)嵌套和執(zhí)行順序問(wèn)題最重要的我感覺(jué)是解決順序問(wèn)題。 現(xiàn)在不會(huì)用Promise都不好意思說(shuō)自己是前端,Promise為什么火起來(lái),一句話解決了回調(diào)嵌套和執(zhí)行順序問(wèn)題最重要的我感覺(jué)是解決順序問(wèn)題。 不過(guò)開(kāi)始寫(xiě)之前我們先看看,promise怎么解決問(wèn)題,怎么用。列舉一個(gè)順序加載圖片demo: //需求 加載三張圖片 img1,im...

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

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

0條評(píng)論

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