HTML5学习笔记——promise

promise

 promise是一个对象,可以获取异步操作的消息。核心概念是“确保一件事情做完之后,再做另一件事情”。

promise的状态

 (1)Pending:(进行中)

 (2)Resolved:(已定型,等价于Fulfilled,已成功)

 (3)Rejected:(已失败)

promise对象的特点:

  1)对象的状态不受外界的影响

      只有异步操作的结果才能决定当前是哪一种状态,任何其他操作都无法改变这个状态。

     “promise”的名字正是由这个特点而来,承诺,即表示其他手段无法改变

  2)一旦状态改变就不会再变,任何时候都可以得到这个结果。

      promise对象状态的改变只有两种可能:

      ① Pending => Fulfilled(Resolved)

      ② Pending => Rejected

      只要这两种情况发生,状态就凝固了,不会再变。

promise的优点

  1)解决回调地狱的问题;

  2)更好地进行错误捕获;

  详细解析参见:http://www.hangge.com/blog/cache/detail_1635.html

promise的缺点

 1)无法取消promise,一旦创建它就会立即执行,无法中途取消;

 2)如果不设置回调函数,promise内部抛出的错误不会反应到外部;

 3)当处于Pending状态时,无法得知目前进展到哪一个阶段;

then()方法

  then方法就是把原来的回调函数写法分离出来,在异步操作执行完毕之后,用链式调用的方式执行回调函数;

  (1)例子:定义做饭、吃饭、洗碗三个方法,它们是层层依赖的关系;

            //做饭
            function cook(){
            	console.log('开始做饭');
            	var p=new Promise(function(resolve,reject){
            		setTimeout(function(){
                       console.log('做饭完毕!');
            		   resolve('蛋炒饭');
            		},1000);
            	});
            	return p;
            }
            //吃饭
            function eat(data){
            	console.log('开始吃饭:'+data);
            	var p=new Promise(function(resolve,reject){
            		setTimeout(function(){
            			console.log('吃饭完毕!');
            		    resolve('待洗碗筷');
            		}, 2000);
            	});
               return p;
            }
            //洗碗
            function wash(data){
               console.log('开始洗碗:'+data);
            	var p=new Promise(function(resolve,reject){
            		setTimeout(function(){
            			console.log('洗碗完毕!');
            		    resolve('干净的碗筷');
            		}, 2000);
            	});
               return p;
            }

   (2)使用then链式调用这三个方法

            cook()
            .then(function(data){
            	return eat(data);
            })
            .then(function(data){
            	return wash(data);
            })
            .then(function(data){
            	return console.log(data);
            })

  (3)简化写法如下:

            cook()
            .then(eat)
            .then(wash)
            .then(function(data){
            	return console.log(data);
            });

运行结果如下:

reject()方法

上面样例我们通过 resolve 方法把 Promise 的状态置为完成态,这时 then 方法就能捕捉到变化,并执行“成功”情况的回调。

而 reject 方法就是把 Promise 的状态置为已失败,这时 then 方法执行“失败”情况的回调(then 方法的第二参数)。

1)举例如下:

            //做饭
            function cook(){
            	console.log('开始做饭');
            	var p=new Promise(function(resolve,reject){
            		setTimeout(function(){
                       console.log('做饭完毕!');
                       //失败
            		   reject('烧焦的饭');
            		},1000);
            	});
            	return p;
            }
            //吃饭
            function eat(data){
            	console.log('开始吃饭:'+data);
            	var p=new Promise(function(resolve,reject){
            		setTimeout(function(){
            			console.log('吃饭完毕!');
            			//成功
            		    resolve('待洗碗筷');
            		}, 2000);
            	});
               return p;
            }
            cook()
            .then(eat,function(data){
            	return console.log(data+'没法吃!');
            });

运行结果如下:

2)如果只需要处理失败的情况,则把then中的第一个参数设置为null即可;

            cook()
            .then(null,function(data){
            	return console.log(data+'没法吃!');
            });

 catch()方法

1)它可以和 then 的第二个参数一样,用来指定 reject 的回调

            cook()
            .then(eat)
            .catch(function(data){
            	return console.log(data+'没法吃!');
            });

2)它的另一个作用是,当执行 resolve 的回调(也就是上面 then 中的第一个参数)时,如果抛出异常了(代码出错了),那么也不会报错卡死 js,而是会进到这个 catch 方法中

           //做饭
            function cook(){
            	console.log('开始做饭');
            	var p=new Promise(function(resolve,reject){
            		setTimeout(function(){
                       console.log('做饭完毕!');
                       //失败
            		   resolve('蛋炒饭');
            		},1000);
            	});
            	return p;
            }
            //吃饭
            function eat(data){
            	console.log('开始吃饭:'+data);
            	var p=new Promise(function(resolve,reject){
            		setTimeout(function(){
            			console.log('吃饭完毕!');
            			//成功
            		    resolve('待洗碗筷');
            		}, 2000);
            	});
               return p;
            }
            cook()
            .then(function(data){
            	throw new Error('饭打翻了');
            	eat(data);
            })
            .catch(function(data){
            	return console.log(data);
            });

 运行结果:

这种错误的捕获是非常有用的,因为它能够帮助我们在开发中识别代码错误。比如,在一个 then() 方法内部的任意地方,我们做了一个 JSON.parse() 操作,如果 JSON 参数不合法那么它就会抛出一个同步错误。用回调的话该错误就会被吞噬掉,但是用 promises 我们可以轻松的在 catch() 方法里处理掉该错误。

 3)还可以添加多个 catch,实现更加精准的异常捕获。

somePromise.then(function() {
 return a();
}).catch(TypeError, function(e) {
 //If a is defined, will end up here because
 //it is a type error to reference property of undefined
}).catch(ReferenceError, function(e) {
 //Will end up here if a wasn't defined at all
}).catch(function(e) {
 //Generic catch-the rest, error wasn't TypeError nor
 //ReferenceError
});

 all()方法

promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完毕才执行回调

1)比如下面代码,两个异步操作是并行的,等到它们都执行完成后才会进到then里面。同时all会把所有异步操作的结果放进一个数组中传给then

  //切菜
            function cut(){
            	console.log('开始切菜');
            	var p=new Promise(function(resolve,reject){
            		setTimeout(function(){
                       console.log('切菜完毕!');
                       //成功
            		   resolve('切好的菜');
            		},1000);
            	});
            	return p;
            }
              //烧水
            function boil(){
            	console.log('烧水切菜');
            	var p=new Promise(function(resolve,reject){
            		setTimeout(function(){
                       console.log('烧水完毕!');
                       //成功
            		   resolve('烧好的水');
            		},1000);
            	});
            	return p;
            }
            Promise
            .all([cut(),boil()])
            .then(function(results){
            	console.log('准备工作完毕');
            	console.log(results);
            })

运行结果如下:

race()方法

race 按字面解释,就是赛跑的意思。race 的用法与 all 一样,只不过 all 是等所有异步操作都执行完毕后才执行 then 回调。而 race 的话只要有一个异步操作执行完毕,就立刻执行 then 回调

注意:其它没有执行完毕的异步操作仍然会继续执行,而不是停止

1)这里我们将上面样例的 all 改成 race

           Promise
            .race([cut(),boil()])
            .then(function(results){
            	console.log('准备工作完毕');
            	console.log(results);
            })

运行结果如下:

 

2)race 使用场景很多。比如我们可以用 race 给某个异步请求设置超时时间,并且在超时后执行相应的操作。

//请求某个图片资源
function requestImg(){
    var p = new Promise(function(resolve, reject){
    var img = new Image();
    img.onload = function(){
       resolve(img);
    }
    img.src = 'xxxxxx';
    });
    return p;
}
 
//延时函数,用于给请求计时
function timeout(){
    var p = new Promise(function(resolve, reject){
        setTimeout(function(){
            reject('图片请求超时');
        }, 5000);
    });
    return p;
}
 
Promise
.race([requestImg(), timeout()])
.then(function(results){
    console.log(results);
})
.catch(function(reason){
    console.log(reason);
});

上面代码 requestImg 函数异步请求一张图片,timeout 函数是一个延时 5 秒的异步操作。我们将它们一起放在 race 中赛跑。

  • 如果 5 秒内图片请求成功那么便进入 then 方法,执行正常的流程。
  • 如果 5 秒钟图片还未成功返回,那么则进入 catch,报“图片请求超时”的信息。

 

原文出自:www.hangge.com  转载:http://www.hangge.com/blog/cache/detail_1638.html 

猜你喜欢

转载自blog.csdn.net/baidu_39067385/article/details/81876848
今日推荐