深入EcmaScript6 Promise,并手寫實現(xiàn)。

首先,先來看Promise用法,Promise主要用于異步,在之前的JS,除了上傳圖片,以及Ajax,幾乎沒有要用到異步的地方。但是Node.JS的出現(xiàn),改變了這一現(xiàn)象,因為在Node出現(xiàn)的時候,后端語言,Java,Python,PHP已經(jīng)占據(jù)了后端的主要份額,要想脫引而出,就要有一些其他語言沒有的特點,Node的特點,就是大量回調(diào)來處理并發(fā), 所以會用到大量的回調(diào)函數(shù),Promise就登場了,當(dāng)然,ES7出現(xiàn)的asyns和await更是將回調(diào)完美的展現(xiàn)出來,這點在Koa2中,大量運用。Promise究竟為何物,我們先來揭開Promise的用法吧:

不用Promise的情況:

                const ajax = function(callback){
                    console.log("start");
                    setTimeout(()=>{
                        callback&&callback.call();
                    },1000)
                }
                ajax(function(){
                    console.log("Hello World");
                })

我們定義一個ajax方法,里面?zhèn)魅胍粋€方法,用setTimeout模擬發(fā)送請求的操作,然后在一秒鐘,輸出這個方法,結(jié)果也輸出正確。

Promise基本使用:

                const ajax = function(){
                    console.log("start");
                    return new Promise(function(resolve,reject){
                        setTimeout(()=>{
                            resolve("hello");
                        },1000)
                    })
                }
                ajax().then((value)=>{
                    console.log(value,"world");
                })

和上文 一樣,只不過這次是返回一個Promise對象,Promise對象可以鏈?zhǔn)秸{(diào)用then方法,進行下一步操作。

Promise鏈?zhǔn)秸{(diào)用:

                const ajax = function(){
                    console.log("start");
                    return new Promise(function(resolve,reject){
                        setTimeout(function(){
                            resolve()
                        },1000);
                    })
                }
                ajax().then(function(){
                    return new Promise(function(resolve,reject){
                        setTimeout(function(){
                            resolve()
                        },2000);
                    })
                }).then(()=>{
                    console.log("Hello World");
                })

注意,then方法,會默認(rèn)返回一個Promise對象,比如return 1,這個1,就對應(yīng)在下次then(value=>{})的value值,但是這樣功能太少了,比如說拋出錯誤,不好維護,所以還是應(yīng)該寫return new Promise();

Promise鏈?zhǔn)秸{(diào)用的復(fù)雜情形:

new Promise(resolve=>{
                    console.log("start1");
                    setTimeout(()=>{
                        resolve(100);
                    },1000);
                })
                .then(value=>{
                    return new Promise(resolve=>{
                        console.log("start2");
                        console.log(value);
                        setTimeout(()=>{
                            resolve(200);
                        },1000);
                    })
                })
                .then(value=>{
                    return new Promise(resolve=>{
                        console.log("start3");
                        console.log(value);
                        setTimeout(()=>{
                            resolve(300);
                        },1000);
                    })
                })

第一個方法,返回的結(jié)果參數(shù),會被第二個方法執(zhí)行,第二個方法返回的參數(shù)會被第三個執(zhí)行。

Promise報錯的處理:

const ajax = function(num){
                    console.log("start");
                    return new Promise(function(resolve,reject){
                        if(num>5){
                            resolve();
                        }else{
                            throw new Errow("出錯了");
                        }
                    })
                }
                ajax(3).then(()=>{
                    console.log("Hello World");
                }).catch((err)=>{
                    console.log(err);
                })

建議即使只需要then,還是應(yīng)該寫catch,捕獲異常。

Promise高級篇:

所有圖片加載完再添加到頁面:

function loadImg(src) {
                    return new Promise((resolve, reject) => {
                        let img = document.createElement('img');
                        img.src = src;
                        img.onload = function() {
                            resolve(img);
                        }
                        img.onerror = function(err) {
                            reject(err);
                        }
                    })
                }
                function showImgs(imgs) {
                    imgs.forEach(function(img) {
                        document.body.appendChild(img);
                    })
                }
                Promise.all([
                    loadImg('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1559449634314&di=56a92121182ba40c4a640c053dc0c64b&imgtype=0&src=http%3A%2F%2Fb.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F9825bc315c6034a8ef5250cec5134954082376c9.jpg'),
                    loadImg('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1559449650753&di=5642d7deef9e1e63b6f3868c75b625f0&imgtype=0&src=http%3A%2F%2Fg.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2Fc2cec3fdfc03924590b2a9b58d94a4c27d1e2500.jpg'),
                    loadImg('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1559449650745&di=6d65c12f144a14bb2593901da1e995a1&imgtype=0&src=http%3A%2F%2Fh.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F0b46f21fbe096b63491b16ea06338744ebf8ac0e.jpg')
                ]).then(showImgs)

有一個圖片加載完就添加到頁面:

function loadImg(src){
                    return new Promise((resolve,reject)=>{
                      let img=document.createElement('img');
                      img.src=src;
                      img.onload=function(){
                        resolve(img);
                      }
                      img.onerror=function(err){
                        reject(err);
                      }
                    })
                  }
                
                  function showImgs(img){
                    let p=document.createElement('p');
                    p.appendChild(img);
                    document.body.appendChild(p)
                  }
                
                  Promise.race([
                    loadImg('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1559449634314&di=56a92121182ba40c4a640c053dc0c64b&imgtype=0&src=http%3A%2F%2Fb.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F9825bc315c6034a8ef5250cec5134954082376c9.jpg'),
                    loadImg('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1559449650753&di=5642d7deef9e1e63b6f3868c75b625f0&imgtype=0&src=http%3A%2F%2Fg.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2Fc2cec3fdfc03924590b2a9b58d94a4c27d1e2500.jpg'),
                    loadImg('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1559449650745&di=6d65c12f144a14bb2593901da1e995a1&imgtype=0&src=http%3A%2F%2Fh.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%210b46f21fbe096b63491b16ea06338744ebf8ac0e.jpg')
                  ]).then(showImgs)

實現(xiàn)隊列:

              function queue(things) {
                    let promise = Promise.resolve();
                    things.forEach(element => {
                        promise = promise.then(() => {
                            return new Promise(resolve => {
                                setTimeout(() => {
                                    console.log(element)
                                    resolve('ok');
                                }, 1000);
                            });
                        })
                    });
                }
                queue(['a', 'b', 'c']);

可依靠這個實現(xiàn)JQuery的animate隊列。

ES7寫法:

                async function queue(arr) {
                  let res = null
                  for (let promise of arr) {
                    res = await promise(res)
                  }
                  return await res
                }
                queue(["a", "b", "c"])
                  .then(data => {
                    console.log(data)// abc
                  })

Promise.reduce也可以用來順序執(zhí)行函數(shù),但是可使用的場景非常有限,一般用來讀取文件信息。

手寫Promise實現(xiàn):

                const PENDING = "pending";
                const RESOLVED = "resolved";
                const REJECTED = "rejected";
                function MyPromise(fn){
                    let that = this;
                    that.state = PENDING;
                    that.value = null;
                    that.resolvedCallbacks = [];
                    that.rejectedCallbacks = [];
                    function resolve(value){
                        if(that.state === PENDING){
                            that.state = RESOLVED;
                            that.value = value;
                            that.resolvedCallbacks.map(callback=>callback(that.value))
                        }
                    }
                    function reject(value){
                        if(that.state === PENDING){
                            that.state = REJECTED;
                            that.value = value;
                            that.rejectedCallbacks.map(callback=>callback(that.value))
                        }
                    }
                    try{
                        fn(resolve,reject)
                    }catch(e){
                        reject(e)
                    }
                }
                
                
                MyPromise.prototype.then = function(onFulfilled,onRejected){
                    let that = this;
                    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
                    onRejected = typeof onRejected === 'function' ? onRejected : r=>{throw r};
                    if(that.state === PENDING){
                        that.resolvedCallbacks.push(onFulfilled)
                        that.rejectedCallbacks.push(onRejected)
                    }
                    if(that.state === RESOLVED){
                        onFulfilled(that.value);
                    }
                    if(that.state === REJECTED){
                        onRejected(that.value);
                    }
                }
                
                const ajax = function(){
                    console.log("start");
                    return new MyPromise(function(resolve,reject){
                        setTimeout(()=>{
                            resolve("hello");
                        },1000)
                    })
                }
                ajax().then((value)=>{
                    console.log(value,"world");
                })
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Promise 對象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,836評論 1 56
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點點福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運大...
    HetfieldJoe閱讀 8,780評論 0 29
  • Promiese 簡單說就是一個容器,里面保存著某個未來才會結(jié)束的事件(通常是一個異步操作)的結(jié)果,語法上說,Pr...
    雨飛飛雨閱讀 3,491評論 0 19
  • 目錄:Promise 的含義基本用法Promise.prototype.then()Promise.prototy...
    BluesCurry閱讀 1,565評論 0 8
  • 一、Promise的含義 Promise在JavaScript語言中早有實現(xiàn),ES6將其寫進了語言標(biāo)準(zhǔn),統(tǒng)一了用法...
    Alex灌湯貓閱讀 888評論 0 2

友情鏈接更多精彩內(nèi)容