彻底理解Javascript 中的 Promise

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了彻底理解Javascript 中的 Promise相关的知识,希望对你有一定的参考价值。

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!

 

 

 
 
 
 

  

 
 
 
 
 
 
 

以上是关于彻底理解Javascript 中的 Promise的主要内容,如果未能解决你的问题,请参考以下文章

彻底理解JavaScript中的this

理解js中的Error

低门槛彻底理解JavaScript中的深拷贝和浅拷贝

玩转JavaScript OOP[3]——彻底理解继承和原型链

JavaScript中原型对象的彻底理解

JavaScript:理解Promise方法