天行健, 君子以自强不息
Sunny's Blog
Title

ES6 Demos(十一) Promises and Asynchronous Programming(Promise与异步编程)

JS 引擎建立在单线程事件循环的概念上, 目前js处理异步调用的模式:

1.事件模式:你需确保所有的事件处理程序都能在事件第一次触发之前被绑定完毕

2.回调模式:

要是你想让两个异步操作并行运行,并且在它们都结束后提醒你,那该怎么做?

要是你想同时启动两个异步操作,但只采用首个结束的结果,那又该怎么做? 避免回掉陷阱

事件模式倾向于在出错时不被触发,而在回调函数模式中你必须始终记得检查错误参数,Promise 能大幅度改善这种情况

Demo1: Promise 基础

Promise 是为异步操作的结果所准备的占位符。函数可以返回一个 Promise,而不必订阅一个事件或向函数传递一个回调参数,就像这样:

     
                // readFile 承诺会在将来某个时间点完成
                let promise = readFile("example.txt");

                // 在此代码中, readFile() 实际上并未立即开始读取文件,这将会在稍后发生。
                // 此函数反而会返回一个 Promise 对象以表示异步读取操作,因此你可以在将来再操作它。          
            

Demo2: Promise 的生命周期

1.挂起态(pending state) == 未决的( unsettled )。

异步操作结束之后,已决的( settled )

2-1.已完成( fulfilled ): Promise 的异步操作已成功结束

2-2.已拒绝( rejected ): Promise 的异步操作未成功结束

"pending" 、 "fulfilled" 或 "rejected" ,以反映 Promise 的状态。但是这些属性是不可访问到的,但是我们可以使用 then() 方法在 Promise 的状态改变时执行一些特定操作。

it means we can't get pending/fulfilled/rejected deractly, but we can do some options when its status changed with 'then'.

Demo3: then/catch

then() 方法在所有的 Promise 上都存在,并且接受两个参数。第一个参数是完成调用后的回掉,第二个参数是拒绝调用后的回掉, then的这两个参数都是可选的

用这种方式实现 then() 方法的任何对象都被称为一个 thenable 。所有的 Promise 都是thenable ,反之则未必成立。

 
                function test (ready) {
                  return new Promise(function (resolve, reject) {
                      if (ready) {
                          resolve("success!");
                      } else {
                          reject("error!");
                      }
                  });
                }

                test(true).then(function (message) {
                  alert(message);
                }, function (error) {
                  alert(error);
                }); //success

                test(false).then(function (message) {
                  alert(message);
                }, function (error) {
                  alert(error);
                }); //error

                //catch 用来捕获错误的简写方法
                //then(fn).catch(fn),相当于 then(fn).then(null, fn)
                test(false).catch(function(message){
                  alert(message);
                }); //error


                // 即使完成或拒绝处理函数在 Promise 已经被解决之后才添加到作业队列,它们仍然会被执行。
                // 这允许你随时添加新的完成或拒绝处理函数,并保证它们会被调用。

                var promise = test(true);
                promise.then(function(data){
                    console.log(data); //success
                    // promise此时已经被完成了,但是仍然可以执行then
                    promise.then(function(data){
                        console.log(data); //success
                    })
                })            
            

Demo4: 创建未决的 Promise

                let promise = new Promise(function(resolve, reject) {
                    console.log("Promise");
                    resolve();
                });

                //这里面的then等同于setTimeout,有延时效果
                //这是因为完成处理函数与拒绝处理函数总是会在执行器的操作结束后被添加到作业队列的尾部

                promise.then(function() {
                    console.log("Resolved.");
                });

                console.log("Hi!");
                // Promise
                // Hi!
                // Resolved.
            

Demo5: 创建已决的 Promise

                // 1.Promise.resolve() 方法接受单个参数并会返回一个处于完成态的 Promise
                let promise = Promise.resolve(42);

                promise.then(function(value) {
                    console.log(value); // 42
                });

                // 2.使用 Promise.reject() 方法来创建一个已拒绝的 Promise

                let promise = Promise.reject(42);

                promise.catch(function(value) {
                    console.log(value); // 42
                });
            

Demo6: 非 Promise 的 Thenable

                // 当一个对象拥有一个能接受 resolve 与 reject 参数的 then() 方法,
                // 该对象就会被认为是一个非 Promise 的 thenable ,就像这样:

                let thenable = {
                    then: function(resolve, reject) {
                        resolve(42);
                    }
                };

                // 此例中的 thenable 对象,除了 then() 方法之外没有任何与 Promise 相关的特征。
                // 你可以调用 Promise.resolve() 来将 thenable 转换为一个已完成的 Promise :

                let p1 = Promise.resolve(thenable);

                p1.then(function(value) {
                    console.log(value); // 42
                });

                // 使用 Promise.resolve() ,同样还能从一个 thenable 创建一个已拒绝的 Promise :

                let thenable = {
                    then: function(resolve, reject) {
                        reject(42);
                    }
                };

                let p1 = Promise.resolve(thenable);

                p1.catch(function(value) {
                    console.log(value); // 42
                });


                // 当你不能确定一个对象是否是 Promise 时,将该对象传递给 Promise.resolve() 或 Promise.reject() 
                // (取决于你的预期结果)是能找出的最好方式,因为传入真正的 Promise 只会被直接传递出来,并不会被修改
            

Demo7: 执行器错误

 
                // 如果在执行器内部抛出了错误,那么 Promise 的拒绝处理函数就会被调用。

                let promise = new Promise(function(resolve, reject) {
                    throw new Error("Explosion!");
                });

                promise.catch(function(error) {
                    console.log(error.message); // "Explosion!"
                }); 
            

Demo8: 全局的 Promise 拒绝处理

unhandledrejection :当一个 Promise 被拒绝、而在事件循环的一个轮次中没有任何拒绝处理函数被调用,该事件就会被触发;

rejectionHandled :若一个 Promise 被拒绝、并在事件循环的一个轮次之后再有拒绝处理函数被调用,该事件就会被触发。

                let rejected;

                window.onunhandledrejection = function(event) {
                    console.log(event.type); // "unhandledrejection"
                    console.log(event.reason.message); // "Explosion!"
                    console.log(rejected === event.promise); // true
                };

                window.onrejectionhandled = function(event) {
                    console.log(event.type); // "rejectionhandled"
                    console.log(event.reason.message); // "Explosion!"
                    console.log(rejected === event.promise); // true
                };

                rejected = Promise.reject(new Error("Explosion!"));
            

Demo9: 串联 Promise

 
                let p1 = new Promise(function(resolve, reject) {
                    resolve(42);
                });

                p1.then(function(value) {
                    console.log(value);
                }).then(function() {
                    console.log("Finished");
                });

                let p1 = new Promise(function(resolve, reject) {
                    reject(42);
                });

                p1.catch(function(value) {
                // 第一个完成处理函数
                    console.log(value); // "42"
                return value + 1;
                }).then(function(value) {
                // 第二个完成处理函数
                    console.log(value); // "43"
                });
            

Demo10: 在 Promise 链中返回 Promise

  
                let p1 = new Promise(function(resolve, reject) {
                    resolve(42);
                });
                let p2 = new Promise(function(resolve, reject) {
                    reject(43);
                });
                p1.then(function(value) {
                    // 第一个完成处理函数
                    console.log(value); // 42
                    return p2;
                }).then(function(value) {
                    // 第二个完成处理函数
                    console.log(value); // 永不被调用
                });


                let p1 = new Promise(function(resolve, reject) {
                    resolve(42);
                });
                let p2 = new Promise(function(resolve, reject) {
                    reject(43);
                });
                p1.then(function(value) {
                    // 第一个完成处理函数
                    console.log(value); // 42
                    return p2;
                }).catch(function(value) {
                    // 拒绝处理函数
                    console.log(value); // 43
                });
            

Demo11: 响应多个 Promise

                Promise.all() 方法

                // Promise.all() 方法接收单个可迭代对象(如数组)作为参数,并返回一个 Promise 。
                // 这个可迭代对象的元素都是 Promise ,只有在它们都完成后,所返回的 Promise 才会被完成。

                let p1 = new Promise(function(resolve, reject) {
                    resolve(42);
                });
                let p2 = new Promise(function(resolve, reject) {
                    resolve(43);
                });
                let p3 = new Promise(function(resolve, reject) {
                    resolve(44);
                });
                let p4 = Promise.all([p1, p2, p3]);

                p4.then(function(value) {
                    console.log(Array.isArray(value)); // true
                    console.log(value[0]); // 42
                    console.log(value[1]); // 43
                    console.log(value[2]); // 44
                });

                // 若传递给 Promise.all() 的任意 Promise 被拒绝了,那么方法所返回的 Promise 就会立刻被拒绝,
                // 而不必等待其他的 Promise 结束


                Promise.race() 方法

                // Promise.race() 提供了监视多个 Promise 的一个稍微不同的方法, 
                // 一旦来源 Promise 中有一个被解决,所返回的 Promise 就会立刻被解决。

                let p1 = Promise.resolve(42);

                let p2 = new Promise(function(resolve, reject) {
                    resolve(43);
                });

                let p3 = new Promise(function(resolve, reject) {
                    resolve(44);
                });

                let p4 = Promise.race([p1, p2, p3]);

                p4.then(function(value) {
                    console.log(value); // 42
                });
            
            
地势坤,君子以厚德载物