徹底理解Javascript 中的 Promise

BerryTVB 8年前發布 | 22K 次閱讀 Promise JavaScript開發

ES6原生提供了 Promise 對象。

到底是何方妖怪呢?打出來看看:

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

Promise 對象有以下兩個特點。

(1)對象的狀態不受外界影響。Promise 對象代表一個異步操作,有三種狀態: Pending(進行中)、Resolved(已完成,又稱 Fulfilled)和 Rejected(已失敗) 。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。這也是 Promise 這個名字的由來,它的英語意思就是「承諾」,表示其他手段無法改變。

(2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise 對象的狀態改變,只有兩種可能:從 Pending 變為 Resolved 和從 Pending 變為 Rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果。就算改變已經發生了,你再對 Promise 對象添加回調函數,也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。

有了 Promise 對象,就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。此外,Promise 對象提供統一的接口,使得控制異步操作更加容易。

Promise 也有一些缺點。首先,無法取消 Promise,一旦新建它就會立即執行,無法中途取消。其次,如果不設置回調函數,Promise 內部拋出的錯誤,不會反應到外部。第三,當處于 Pending 狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。

廢話不多說,直接上demo:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8" />
        <title>Promise 學習筆記</title>
        <script type="text/javascript">
            window.onload = function() {
                function pms1() {
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            console.log('執行任務1');
                            resolve('執行任務1成功');
                        }, 2000);
                    });
                }

                function pms2() {
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            console.log('執行任務2');
                            resolve('執行任務2成功');
                        }, 2000);
                    });
                }

                function pms3() {
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            console.log('執行任務3');
                            resolve('執行任務3成功');
                        }, 2000);
                    });
                }
                pms1().then(function(data) {
                        console.log('第1個回調:' + data);
                        return pms2();
                    })
                    .then(function(data) {
                        console.log('第2個回調:' + data);
                        return pms3();
                    })
                    .then(function(data) {
                        console.log('第3個回調:' + data);
                        return '還沒完!該結束了吧!'
                    }).then(function(data) {
                        console.log(data);
                    });
            }
        </script>
    </head>

    <body>

    </body>

</html>

怎么樣?是不是灰常簡單啊!

demo2:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
        <script type="text/javascript">
            window.onload = function() {
                function pms1() {
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            var num = Math.ceil(Math.random() * 10); //生成1-10的隨機數
                            if(num <= 5) {
                                resolve(num);
                            } else {
                                reject('數字太大了吧!');
                            }
                        }, 2000);
                    });
                }
                setInterval(function() {
                    pms1().then(function(data) {    //小于等于5的
                        console.log(data);
                    }, function(data) {     //大于的
                        console.log(data);
                    })
                }, 1000);
            }
        </script>
    </head>

    <body>
    </body>

</html>

Promise 構造函數接受一個函數作為參數,該函數的兩個參數分別是 resolve 方法和 reject 方法。

如果異步操作成功,則用 resolve 方法將 Promise 對象的狀態,從「未完成」變為「成功」(即從 pending 變為 resolved);

如果異步操作失敗,則用 reject 方法將 Promise 對象的狀態,從「未完成」變為「失敗」(即從 pending 變為 rejected)。

all的用法:

demo

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8" />
        <title>Promise 學習筆記</title>
        <script type="text/javascript">
            window.onload = function() {
                function pms1() {
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            console.log('執行任務1');
                            resolve('執行任務1成功');
                        }, 2000);
                    });
                }

                function pms2() {
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            console.log('執行任務2');
                            resolve('執行任務2成功');
                        }, 2000);
                    });
                }

                function pms3() {
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            console.log('執行任務3');
                            resolve('執行任務3成功');
                        }, 2000);
                    });
                }
                Promise.all([pms1(), pms2(), pms3()]).then(function(data) {
                    console.log(data);
                    console.log({}.toString.call(data));
                })
            }
        </script>
    </head>

    <body>

    </body>

</html>

用Promise.all來執行,all接收一個數組參數,里面的值最終都算返回Promise對象。這樣,三個異步操作的并行執行的,等到它們都執行完后才會進到then里面。那么,三個異步操作返回的數據哪里去了呢?都在then里面呢,all會把所有異步操作的結果放進一個 數組 中傳給then,就是上面的results。

race的用法

all方法的效果實際上是「誰跑的慢,以誰為準執行回調」,那么相對的就有另一個方法「誰跑的快,以誰為準執行回調」,這就是race方法,這個詞本來就是賽跑的意思。race的用法與all一樣,我們把上面runAsync1的延時改為1秒來看一下:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8" />
        <title>Promise 學習筆記</title>
        <script type="text/javascript">
            window.onload = function() {
                function pms1() {
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            console.log('執行任務1');
                            resolve('執行任務1成功');
                        }, 1000);
                    });
                }

                function pms2() {
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            console.log('執行任務2');
                            resolve('執行任務2成功');
                        }, 2000);
                    });
                }

                function pms3() {
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            console.log('執行任務3');
                            resolve('執行任務3成功');
                        }, 3000);
                    });
                }
                Promise.race([pms1(), pms2(), pms3()]).then(function(data) {
                    console.log(data);   //注意上面的延時時間
                })
            }
        </script>
    </head>

    <body>

    </body>

</html>

看到沒: 只有第一個執行了回調!

在then里面的回調開始執行時,runAsync2()和runAsync3()并沒有停止,仍舊再執行。于是再過1秒后,輸出了他們結束的標志。

這個race有什么用呢?使用場景還是很多的,比如我們可以用race給某個異步請求設置超時時間,并且在超時后執行相應的操作。

再來看看jquery里面的 $.Deferred:

jquery用$.Deferred實現了Promise規范,$.Deferred是個什么玩意呢?還是老方法,打印出來看看,先有個直觀印象:

var def = $.Deferred();
console.log(def);

輸出如下:

$.Deferred()返回一個對象,我們可以稱之為Deferred對象,上面掛著一些熟悉的方法如:done、fail、then等。jquery就是用這個Deferred對象來注冊異步操作的回調函數,修改并傳遞異步操作的狀態。

Deferred對象的基本用法如下,為了不與ajax混淆,我們依舊舉setTimeout的例子:

<!doctype html>
<html lang="en">

    <head>
        <meta charset="UTF-8" />
        <title>Document</title>
        <script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
        <script type="text/javascript">
            $(function() {
                function runAsync() {
                    var def = $.Deferred();
                    setTimeout(function() {
                        console.log('執行完成');
                        def.resolve('隨便什么數據');
                    }, 2000);
                    return def;
                }
                runAsync().then(function(data) {
                    console.log(data)
                });
            })
        </script>
    </head>

    <body>

    </body>

</html>

在runAsync函數中,我們首先定義了一個def對象,然后進行一個延時操作,在2秒后調用def.resolve(),最后把def作為函數的返回。調用runAsync的時候將返回def對象,然后我們就可以.then來執行回調函數。

是不是感覺和ES6的Promise很像呢?

區別在何處一看便知。由于jquery的def對象本身就有resolve方法,所以我們在創建def對象的時候并未像ES6這樣傳入了一個函數參數,是空的。在后面可以直接def.resolve()這樣調用。

<!doctype html>
<html lang="en">

    <head>
        <meta charset="UTF-8" />
        <title>Document</title>
        <script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
        <script type="text/javascript">
            $(function() {
                function runAsync() {
                    var def = $.Deferred();
                    setTimeout(function() {
                        console.log('執行完成');
                        def.resolve('隨便什么數據');
                    }, 2000);
                    return def;
                }
                var pms=runAsync();
                pms.then(function(data) {
                    console.log(data)
                });
                pms.resolve('我穿越了!')
            })
        </script>
    </head>

    <body>

    </body>

</html>

這樣也有一個弊端,因為執行runAsync()可以拿到def對象,而def對象上又有resolve方法,那么豈不是可以在外部就修改def的狀態了?比如我把上面的代碼修改如下:

現象會如何呢?并不會在2秒后輸出“執行完成”,而是直接輸出“我穿越了”。因為我們在異步操作執行完成之前,沒等他自己resolve,就在外部給resolve了。這顯然是有風險的,比如你定義的一個異步操作并指定好回調函數,有可能被別人給提前結束掉,你的回調函數也就不能執行了。

怎么辦?jquery提供了一個promise方法,就在def對象上,他可以返回一個受限的Deferred對象,所謂受限就是沒有resolve、reject等方法,無法從外部來改變他的狀態,用法如下:

<!doctype html>
<html lang="en">

    <head>
        <meta charset="UTF-8" />
        <title>Document</title>
        <script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
        <script type="text/javascript">
            $(function() {
                function runAsync() {
                    var def = $.Deferred();
                    setTimeout(function() {
                        console.log('執行完成');
                        def.resolve('隨便什么數據');
                    }, 2000);
                    return def.promise();
                }
                var pms=runAsync();
                pms.then(function(data) {
                    console.log(data)
                });
                //pms.resolve('我穿越了!');    //這一句會報錯jquery-3.1.1.min.js:2 Uncaught TypeError: pms.resolve is not a function
            })
        </script>
    </head>

    <body>

    </body>

</html>

 

then的鏈式調用

既然Deferred也是Promise規范的實現者,那么其他特性也必須是支持的。鏈式調用的用法如下:

<!doctype html>
<html lang="en">

    <head>
        <meta charset="UTF-8" />
        <title>Document</title>
        <script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
        <script type="text/javascript">
            $(function() {
                function runAsync() {
                    var def = $.Deferred();
                    setTimeout(function() {
                        console.log('執行完成');
                        def.resolve('隨便什么數據');
                    }, 2000);
                    return def.promise();
                }
                var pms = runAsync();

                pms.then(function(data) {
                        console.log('1:' + data);
                        return runAsync();
                    })
                    .then(function(data) {
                        console.log('2:' + data);
                        return runAsync();
                    })
                    .then(function(data) {
                        console.log('3:' + data);
                    });
                //pms.resolve('我穿越了!');    //這一句會報錯jquery-3.1.1.min.js:2 Uncaught TypeError: pms.resolve is not a function
            })
        </script>
    </head>

    <body>

    </body>

</html>

done與fail

我們知道,Promise規范中,then方法接受兩個參數,分別是執行完成和執行失敗的回調,而jquery中進行了增強,還可以接受第三個參數,就是在pending狀態時的回調,如下:

deferred.then( doneFilter [, failFilter ] [, progressFilter ] )

除此之外,jquery還增加了兩個語法糖方法,done和fail,分別用來指定執行完成和執行失敗的回調,也就是說這段代碼:

d.then(function(){
    console.log('執行完成');
}, function(){
    console.log('執行失敗');
});

與這段代碼是等價的:

d.done(function(){
    console.log('執行完成');
})
.fail(function(){
    console.log('執行失敗');
});

always的用法

jquery的Deferred對象上還有一個always方法,不論執行完成還是執行失敗,always都會執行,有點類似ajax中的complete。不贅述了。

$.when的用法

jquery中,還有一個$.when方法來實現Promise,與ES6中的all方法功能一樣,并行執行異步操作,在所有的異步操作執行完后才執行回調函數。不過$.when并沒有定義在$.Deferred中,看名字就知道,$.when,它是一個單獨的方法。與ES6的all的參數稍有區別,它接受的并不是數組,而是多個Deferred對象,如下:

$.when(runAsync(), runAsync2(), runAsync3())
.then(function(data1, data2, data3){
    console.log('全部執行完成');
    console.log(data1, data2, data3);
});

jquery中沒有像ES6中的race方法嗎?就是以跑的快的為準的那個方法。對的,jquery中沒有。

以上就是jquery中Deferred對象的常用方法了,還有一些其他的方法用的也不多,干脆就不記它了。接下來該說說ajax了。

ajax與Deferred的關系

jquery的ajax返回一個受限的Deferred對象,還記得受限的Deferred對象吧,也就是沒有resolve方法和reject方法,不能從外部改變狀態。想想也是,你發一個ajax請求,別人從其他地方給你取消掉了,也是受不了的。

既然是Deferred對象,那么我們上面講到的所有特性,ajax也都是可以用的。比如鏈式調用,連續發送多個請求:

req1 = function(){
    return $.ajax(/*...*/);
}
req2 = function(){
    return $.ajax(/*...*/);
}
req3 = function(){
    return $.ajax(/*...*/);
}

req1().then(req2).then(req3).done(function(){
    console.log('請求發送完畢');
});

明白了ajax返回對象的實質,那我們用起來就得心應手了。

success、error與complete

這三個方法或許是我們用的最多的,使用起來是這樣的:

$.ajax(/*...*/)
.success(function(){/*...*/})
.error(function(){/*...*/})
.complete(function(){/*...*/})

分別表示ajax請求成功、失敗、結束的回調。這三個方法與Deferred又是什么關系呢?其實就是語法糖,success對應done,error對應fail,complete對應always,就這樣,只是為了與ajax的參數名字上保持一致而已,更方便大家記憶,看一眼源碼:

deferred.promise( jqXHR ).complete = completeDeferred.add;
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail;

complete那一行那么寫,是為了減少重復代碼,其實就是把done和fail又調用一次,與always中的代碼一樣。deferred.promise( jqXHR )這句也能看出,ajax返回的是受限的Deferred對象。

jquery加了這么些個語法糖,雖然上手門檻更低了,但是卻造成了一定程度的混淆。一些人雖然這么寫了很久,卻一直不知道其中的原理,在面試的時候只能答出一些皮毛,這是很不好的。這也是我寫這篇文章的緣由。

看一個promise.js庫:

/*!
 * Promise JavaScript Library v2.0.0
 */
;
(function(window) {
    var _promise = function(thens) {
        this.thens = thens || [];
        this.state = "";

        this._CONSTANT = {
            any: "any",
            number: "number",
            resolved: "resolved",
            rejected: "rejected",
            pending: "pending"
        };
    };

    _promise.prototype = {
        resolve: function() {
            if(this.state == this._CONSTANT.pending) {
                this.state = this._CONSTANT.resolved;
                return;
            }
            if(this.state !== "") return;
            if(this.promiseArr) {
                for(var i = 0, j = this.promiseArr.length; i < j; i++) {
                    this.promiseArr[i].resolveCount++;
                }
                if(this.promiseArr[0].action !== this._CONSTANT.any) {
                    if(this.resolveCount !== this.promiseArr.length) {
                        return;
                    }
                } else {
                    if(this.resolveCount > 1) {
                        return;
                    }
                }
            }
            this.state = this._CONSTANT.resolved;
            if(!this.thens) return;
            if(this.thens[0] && this.thens[0].finallyCB) this.thens[0].finallyCB.apply(null, arguments);
            var t, n;
            while(t = this.thens.shift()) {
                if(typeof t === this._CONSTANT.number) {
                    var self = this;
                    setTimeout(function() {
                        var prms = new _promise(self.thens);
                        prms.resolve();
                    }, t);
                    break;
                }
                var doneFn = t.done,
                    action = t.action;
                if(!doneFn) continue;
                if(doneFn instanceof Array) {
                    var arr = [];
                    for(var i = 0, j = doneFn.length; i < j; i++) {
                        var df = doneFn[i];
                        if(df instanceof _promise) {
                            df.thens = this.thens;
                            arr.push(df);
                        } else {
                            var m = df.apply(null, arguments);
                            if(m instanceof _promise) {
                                m.thens = this.thens;
                                arr.push(m);
                            }
                        }
                    }
                    var l = arr.length;
                    if(l === 0) {
                        continue;
                    } else {
                        for(var i = 0; i < l; i++) {
                            arr[i].promiseArr = arr;
                            arr[i].action = action;
                            arr[i].resolveCount = 0;
                        }
                        break;
                    }
                } else {
                    if(doneFn instanceof _promise) {
                        doneFn.thens = this.thens;
                        break;
                    } else {
                        n = doneFn.apply(null, arguments);
                        if(n instanceof _promise) {
                            n.thens = this.thens;
                            break;
                        }
                    }
                    continue;
                }

            }
        },

        reject: function() {
            if(this.state !== "") return;
            if(this.promiseArr && this.promiseArr[0].action === this._CONSTANT.any) {
                if(this.promiseArr[this.promiseArr.length - 1] !== this) {
                    return;
                }
            }
            this.state = this._CONSTANT.rejected;
            if(!this.thens) return;
            if(this.thens[0] && this.thens[0].finallyCB) this.thens[0].finallyCB.apply(null, arguments);
            var t, n;
            while(t = this.thens.shift()) {
                if(typeof t === this._CONSTANT.number) {
                    var self = this;
                    setTimeout(function() {
                        var prms = new _promise(self.thens);
                        prms.resolve();
                    }, t);
                    break;
                }
                if(t.fail) {
                    n = t.fail.apply(null, arguments);
                    if(n instanceof _promise) {
                        n.thens = this.thens;
                        break;
                    }
                    continue;
                }
                break;
            }
        },

        notify: function() {
            var t = this.thens[0];
            t.progress.apply(null, arguments);
        },

        then: function(done, fail, progress) {
            this.thens.push({
                done: done,
                fail: fail,
                progress: progress
            });
            return this;
        },

        any: function(done, fail, progress) {
            this.thens.push({
                done: done,
                fail: fail,
                progress: progress,
                action: this._CONSTANT.any
            });
            return this;
        },

        done: function(done) {
            if(this.thens.length === 0 || this.thens[this.thens.length - 1].done) {
                this.thens.push({
                    done: done
                });
            } else {
                this.thens[this.thens.length - 1].done = done;
            }
            return this;
        },

        fail: function(fail) {
            if(this.thens.length === 0 || this.thens[this.thens.length - 1].fail) {
                this.thens.push({
                    fail: fail
                });
            } else {
                this.thens[this.thens.length - 1].fail = fail;
            }
            return this;
        },

        progress: function(progress) {
            if(this.thens.length === 0 || this.thens[this.thens.length - 1].progress) {
                this.thens.push({
                    progress: progress
                });
            } else {
                this.thens[this.thens.length - 1].progress = progress;
            }
            return this;
        },

        ensure: function(finallyCB) {
            if(this.thens.length === 0 || this.thens[this.thens.length - 1].finallyCB) {

                this.thens.push({
                    finallyCB: finallyCB
                });
            } else {
                this.thens[this.thens.length - 1].finallyCB = finallyCB;
            }
            return this;
        },

        always: function(alwaysCB, progress) {
            this.thens.push({
                done: alwaysCB,
                fail: alwaysCB,
                progress: progress
            });
            return this;
        },

        wait: function(ms) {
            this.thens.push(~~ms);
            return this;
        }
    }

    var Promise = function(parameter) {
        var prms = new _promise();
        if(parameter) {
            if(arguments.length > 1) {
                prms.thens[0] = {};
                prms.thens[0].done = [];
                prms.thens[0].done.push.apply(prms.thens[0].done, arguments);
                setTimeout(function() {
                    prms.resolve();
                }, 1)
            } else {
                prms = parameter();
                if(prms instanceof _promise) return prms;
            }
        }
        return prms;
    };

    Promise.when = function() {
        var prms = new _promise();
        prms.thens[0] = {};
        prms.thens[0].done = [];
        prms.thens[0].done.push.apply(prms.thens[0].done, arguments);
        setTimeout(function() {
            prms.resolve();
        }, 1)
        return prms;
    };

    Promise.any = function() {
        var prms = new _promise();
        prms.thens[0] = {};
        prms.thens[0].action = prms._CONSTANT.any;
        prms.thens[0].done = [];
        prms.thens[0].done.push.apply(prms.thens[0].done, arguments);
        setTimeout(function() {
            prms.resolve();
        }, 1)
        return prms;
    };

    Promise.timeout = function(promise, ms) {
        setTimeout(function() {
            promise.reject();
        }, ms);
        return promise;
    }

    Promise.gtTime = function(promise, ms) {
        promise.state = promise._CONSTANT.pending;
        setTimeout(function() {
            if(promise.state == promise._CONSTANT.resolved) {
                promise.state = "";
                promise.resolve();
            }
            promise.state = "";
        }, ms);
        return promise;
    }

    if(typeof module === "object" && module && typeof module.exports === "object") {
        module.exports = Promise;
    } else {
        window.Promise = Promise;

        if(typeof define === "function" && define.amd) {
            define("promise", [], function() {
                return Promise;
            });
        }
    }
}(window));

promise.js提供了done和resolve方法,done負責注冊成功的回調函數,resolve負責觸發。

function cb() {
            alert('success')
        }
        var prms = Promise()
        prms.done(cb)
        setTimeout(function() {
            prms.resolve()
        }, 3000)

在3秒之后,瀏覽器將alert  “success”。

當然你也可以通過prms.resolve(“xxx”)傳遞參數給cb函數使用,如:

  function cb(num) {
            alert(num)
        }
        var prms = Promise()
        prms.done(cb)
        setTimeout(function() {
            prms.resolve(1)
        }, 3000)

在3秒之后,瀏覽器將alert  “1”。

fail/reject

fail函數負責注冊失敗的回調函數,reject負責觸發。如:

  function cb() {
            alert('fail')
        }
        var prms = Promise()
        prms.fail(cb)
        setTimeout(function () {
            prms.reject()
        }, 3000)

progress/notify

progress函數負責注冊處理中進度的回調函數,notify負責觸法。如:

 function cb() {
            alert('progress')
        }
        var prms = Promise()
        prms.progress(cb)
        setInterval(function() {
            prms.notify()
        }, 2000)

每隔兩秒瀏覽器會彈出一個progress。

chain

  function cb1() {
            alert('success')
        }
        function cb2() {
            alert('fail')
        }
        function cb3() {
            alert('progress')
        }
        var prms = Promise();
        prms.done(cb1).fail(cb2).progress(cb3)
        setTimeout(function () {
            prms.resolve()
            //prms.reject()
            //prms.notify()

        }, 3000)

then

function fn1() {
            alert('success')
        }
        function fn2() {
            alert('fail')
        }
        function fn3() {
            alert('progress')
        }
        var prms = Promise()
        prms.then(fn1, fn2, fn3)
        prms.resolve()
        prms.reject()
        prms.notify()

當然也支持prms.then().then().then()……….

當then的第一個參數為一個數組的時候,要等所有task都完成:

f1().then([f2_1, f2_2]).then(f3)

如上面的代碼:

f1執行完后,同時執行f2_1和f2_2,當f2_1和f2_2 全部 都執行完成才會執行f3。

any

f1().any([f2_1, f2_2]).then(f3)

f1執行完后,同時執行f2_1和f2_2,當f2_1和f2_2中的 任意一個 執行完成才會執行f3。

always

  var prms = Promise()
        prms.always(function () {
            alert(2)
        })
        setTimeout(function () {
            // prms.resolve()
            prms.reject()
        }, 3000)

always(fn)等同于then(fn,fn),也等同于done(fn).fail(fn)

wait

 function f10() {
            var promise = Promise();
            setTimeout(function () {

                console.log(10);
                promise.resolve();
            }, 4500)

            return promise;
        }

        function f11() {
            var promise = Promise();
            setTimeout(function () {

                console.log(11);
                promise.resolve();
            }, 1500)

            return promise;
        }

        f11().wait(5000).then(f10)  //execute f11 then wait 5000ms then execute f10

ensure

ensure方法類似try…catch..finally中的finally,不管task成功失敗都會執行。

Promise.when

 Promise.when(f1(), f2()).then(f3).then(f4)

        function f1() {
            var promise = Promise();
            setTimeout(function () {

                console.log(1);
                promise.resolve("from f1");
            }, 1500)

            return promise;
        }

        function f2() {
            var promise = Promise();
            setTimeout(function () {

                console.log(2);
                promise.resolve();
            }, 5500)

            return promise;
        }

        function f3() {
            var promise = Promise();
            setTimeout(function () {

                console.log(3);
                promise.resolve();
            }, 1500)

            return promise;

        }

        function f4() {
            var promise = Promise();
            setTimeout(function () {

                console.log(4);
                promise.resolve();
            }, 1500)

            return promise;
        }

上面promise.when的等同簡略寫法也可以是:Promise(f1(),f2()).then….

Promise.any

Promise.any的使用和when一樣,when的意義是等所有task都完成再執行后面的task,而any的意義是任何一個task完成就開始執行后面的task。

Promise.timeout

  Promise.timeout(f1(), 2000).then(f2, function () {
            alert("timeout");
        }).wait(5000).then(f3);
        function f1() {
            var promise = Promise();
            setTimeout(function () {

                console.log(1);
                promise.resolve("from f1");
            }, 1500)

            return promise;
        }

        function f2() {
            var promise = Promise();
            setTimeout(function () {

                console.log(2);
                promise.resolve();
            }, 1500)

            return promise;
        }

        function f3() {
            var promise = Promise();
            setTimeout(function () {

                console.log(3);
                promise.resolve();
            }, 1500)

            return promise;

        }

with wind.js

  <script src="wind-all-0.7.3.js"></script>
    <script src="promise.js"></script>
    <script>

        Wind.Promise.create = function (fn) {
            var prms = Promise();
            fn(prms.resolve, prms.reject);
            return prms;
        }

        var testAsync = eval(Wind.compile("promise", function () {
            for (var i = 0; i < 3; i++) {   //loop 3 times
                var aa = $await(f1());
                alert(aa);                  //alert “from f1” 
                $await(f2().wait(3000));    //execute f2 then wait 3000ms
                $await(f3());
            }
        }));

        testAsync();

        function f1() {
            var promise = Promise();
            setTimeout(function () {
                console.log(1);
                promise.resolve("from f1");
            }, 2500)

            return promise;
        }

        function f2() {
            var promise = Promise();
            setTimeout(function () {
                console.log(2);
                promise.resolve();
            }, 1500)

            return promise;
        }

        function f3() {
            var promise = Promise();
            setTimeout(function () {
                console.log(3);
                promise.resolve();
            }, 1500)

            return promise;
        }
    </script>

That’s all.Have Fun!

 

來自:http://www.cnblogs.com/libin-1/p/5947602.html

 

 本文由用戶 BerryTVB 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!