• Promise对象的基本用法


    主要作用

    1.用来传递异步操作的消息
    2.三种状态:pending、Resolved、Rejected,而且只能从第一种状态转到后两者状态之一。
    3.缺点
    (1)一旦新建就会立即执行
    (2)如果不设置回调函数,Promise内部抛出的错误不会反应到外部
    (3)如果处于Pending状态,不知道目前到底进行到哪一个阶段。
    4.基本用法

    var promise = new Promise(function(resolve,reject){
    	//...
    	if(/*异步操作成功*/){
    		resolve(value);//这个函数是js引擎提供的,不用自己部署,这个value可以传递给then方法的参数
    	}else{
    		reject(error);//这个函数是js引擎提供的,不用自己部署,这个value可以传递给then方法的参数
    	}else{
    	}
    })
    

    接收一个函数作为参数,而这个函数的两个参数也是两个函数,是由js引擎提供,不用自己部署。后一个函数不一定要提供
    resolve函数的作用是将pending转为resolved状态,在异步操作成功的时候调用,reject则是将其转为rejected状态,在异步操作失败的时候调用。

    then()方法

    1.作用:当Promise实例生成以后,可以用then方法分别指定Resolved状态和Rejected状态的回调函数。定义在原型对象Promise.prototype上的,为Promise实例添加状态改变时的回调函数
    2.then方法返回的是一个新的Promise实例,因此可以采用链式写法,即then方法后面还可以调用另一个then方法。

    //异步加载图片
    function loadImageAsync(url){
    	return new Promise(function(resolve,reject){
    		var image = new Image();
    		image.onload = function(){
    			resolve(image);
    		};
    		image.onerror = function(){
    			reject(new Error('cound not load image at'+url));
    		};
    		image.src = url;
    	})
    }
    
    //ajax操作
    var getJSON = function(url){
    	var promise = new Promise(function(resolve,reject){
    		var client = new XMLHttpRequest();
    		client.open("GET",url);
    		client.onreadystatechange = handler;
    		client.responseType = "json";
    		clent.setRequestHeader("Accept","application/json");
    		client.send();
    
    		function handler(){
    			if(this.readyState !== 4){
    				return;
    			}
    			if(this.status === 200){
    				resolve(this.response);//当转为resolved状态的时候,调用then方法
    				//就会把this.response这个值传递给then方法参数中的value。
    			}else{
    				reject(new Error(this.statusText));
    				//当promise的状态转为rejected时,就会把这个错误信息传递给then方法
    			}
    		};
    	});
    	return promise;
    }
    
    getJSON("/post.json").then(function(json)){
    	console.log(json);//这里的json即是上面的this.response
    },function(error){
    	console.log(error);
    }
    
    getJSON("/post.json").then(function(json){
    	return json.post; //这里返回的可能还是一个Promise对象
    }).then(function(post)){
    	//上一个then方法的返回值传递给这个then方法的函数的参数
    });
    

    Promise.prototype.catch()

    1.这个方法是指定发生错误时的回调函数
    注意:如果Promise的状态已经是Resolved,再抛出错误也是无效的。

    var promise = new Promise(function(resolve,reject){
    	resolve("ok");//因为这里已经是resolved状态了,下面再抛出错误也无效
    	throw new Error('test');
    })
    
    promise.then(function(value){
    	console.log(value);
    }).catch(function(error){
    	console.log(error);
    })
    //ok这里只会打印ok
    

    还有要注意的是:

    (1)Promise对象的错误具有“冒泡”性质,一直会向后面传递,直到捕获为止。不过一般来说,不要在then方法中定义Rejected状态的回调函数,最好在外面用catch方法
    (2)还有和传统的try...catch块不同,如果没有使用catch方法来指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应。
    (3)如果在Promise内部,状态已经是resolved了,再抛出错误,这个错误也就是在Promise函数体外抛出的。原因是此时Promise的函数体已经运行结束。
    (4)catch方法返回的还是一个Promise对象,因此后面还可以紧接着调用then方法。

    有两种创建Promise对象实例以及调用它的方法

    //第一种,直接利用new命令,创建一个Promise实例

    var promise = new Promise(function(resolve,reject){
    	//...
    })
    promise.then(function(value){
    	//...
    })
    

    //第二种,用一个函数,然后在其中用return返回一个Promise实例,

    var someAsyncThing = function(){
    	return new Promise(function(resolve,reject){
    		//下面一行会报错
    		resolve(x+2);
    	})
    }
    someAsyncThing().catch(function(error){
    	console.log('oh no',error);
    }).then(function(){
    	console.log('carry on');
    });
    //oh no [ReferenceError: x is not defined]
    //carry on
    

    创建Promise实例和then方法和catch方法之间的关系

    这里只是我的个人理解:
    1.当创建了Promise实例的时候,就会在其中调用两个函数:resolve()和reject(),当resolve()函数成功执行的时候,Promise对象的状态就变成了Resolved,此时就调用then方法,同样的,reject()函数成功执行的时候,Promise对象的状态就变成了Rejected此时也可以调用then方法,但是处理错误的时候,一般推荐使用catch方法。
    2.当在创建实例的过程中,会调用resolve()方法,如果这个方法的后面还有throw命令或者抛出错误,此时得判断这个错误是由Promise函数体内部还是外部抛出的,如果是内部抛出,有无catch都无所谓,如果是外部错误,没有catch的话,就会报错(Uncaught Error)。
    3.还有在创建实例的过程中,resolve方法的参数,如果是值,就会传递给then方法的函数的参数value。如果还是一个Promise对象,就会返回另一个异步操作。

    还有几个小的还很实际的方法

    1.Promise.all():用于将多个Promise实例包装成一个新的Promise实例。
    参数:可以接受一个数组,但是这个数组的所有成员都是Promise对象的实例,如果不是,就会先调用Promise.resolve方法,将参数转为Promise实例。
    也不一定是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例
    2.Promise.race():同样是将多个Promise实例包装成一个新的Promise实例。
    var p = Promise.race([p1,p2,p3]);
    上面的代码中,只要p1,p2,p3中有一个实例率先改变,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就会传递给p的回调函数。同样如果不是Promise实例,就会调用resolve方法来转化为实例。

    var p = Promise.race([
    	fetch('/resource-that-may-a-while'),new Promise(function(resolve,reject){
    		setTimeout(()=>reject(new Error('request timeout')),5000)
    	})
    ])
    p.then(response => console.log(response));
    p.catch(error => console.log(error));
    //上面的代码,如果5秒之内fetch方法无法返回结果,变量p的状态就会变成Rejected,从而触发 catch方法指定的回调函数
    

    3.Promise.resolve()
    这个方法就是得到一个Promise对象。
    参数:可以是值,也可以是具有then方法的对象
    (1)如果是值,如字符串,则返回一个新的Promise对象,那么对象的状态变为resolved,而且参数也会同时传递给回调函数。
    (2)其实也可以允许调用的时候,不带参数
    4.Promise.reject():也会返回一个新的Promise实例,状态为Rejected。而且reason这个参数会被传递给实例的回调函数。

    两个有用的附加方法

    ES6的Promise API提供的方法不是很多,可以自己部署一些有用的方法,下面部署两个不在ES6中但很有用的方法。
    1.done():这个是为了避免Promise对象的回调链,不管以then方法还是catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为Promise内部的错误冒泡到全局)。
    所以,我们提供一个done方法,总是处于回调链的尾端,保证抛出任何可能出现的错误。

    asyncFunc()
    	.then(f1)
    	.catch(r1)
    	.then(f2)
    	.done();
    Promise.prototype.done = function(onFulfilled,onRejected){
    	this.then(onFulfilled,onRejected)
    		.catch(function(reason){
    			//抛出一个全局错误
    			setTimeout(() => {throw reason},0);
    		});
    }
    
    

    由上面可以看出,done方法可以像then方法那样使用,也可以不提供任何参数,但是不管怎么样,done方法都会捕捉到任何可能出现的错误,并向全局抛出。

    2.finally()方法:用于指定不管Promise对象最后状态如何都会执行的操作。它和done方法的最大区别在于,它接受一个普通的回调函数作为参数,该函数不管怎么样都必须执行
    下面是一个例子:服务器使用Promise处理请求,然后使用finally方法关掉服务器

    server.listen(0)
    	.then(function(){
    		//run test
    	})
    	.finally(server.stop);
    Promise.prototype.finally = function(callback){
    	let P = this.constructor;
    	return this.then(
    		value => P.resolve(callback()).then(() => value),//调用resolve函数之后返回一个Promise对象,然后再调用then方法
    		reason => P.resolve(callback()).then(()=> {throw reason})
    	)
    }//㐀Promis对象的 状态如何,都会执行回调函数callback
    

    应用

    1.加载图片:可以将图片的加载写成一个Promise,一旦加载完成,Promise的状态就发生变化。

    const preloadImage = function(path){
    	return new Promise(function(resolve,reject){
    		var image = new Image();
    		image.onload = resolve;
    		image.onerror = reject;
    		image.src = path;
    	})
    }
    

    2.Generator函数和Promise的结合
    使用Generator函数管理流程,遇到异步操作,通常返回一个Promise对象

    //getFoo函数,返回一个Promise对象
    function getFoo(){
    	return new Promise(function(resolve,reject){
    		resolve('foo');
    	})
    }
    
    
    var g = function* (){
    	try{
    		var foo = yield getFoo(); //执行run(g)的时候,这里会返回一个Promise对象,getFoo()是异步操作
    		console.log(foo);
    	}catch(e){
    		console.log(e);
    	}
    };
    //总结一下,调用Generator函数,就会返回一个遍历器对象,代表Generator函数的内部指针,以后每次调用遍历器对象的next方法,就会返回一个包括value和done属性的对象。value的值是yield语句后面那个表达式的值;done属性是一个布尔值。
    //通过run方法来包装异步函数
    function run(generator){
    	var it = generator();
    	function go(result){
    		if(result.done) return result.value;//这里的result是getFoo函数的返回值,也就是一个Promise对象
    		return result.value.then(function(value){
    			return go(it.next(value));//这里不用go执行,直接执行it.next(value)也可以,为什么这里要用go???
    		},function(error){
    			return go(it.throw(error));
    		})
    	}
    	go(it.next());//执行it.next()之后就会返回一个包含value和done属性的对象
    }
    run(g);
    
  • 相关阅读:
    SqlServer触发器的创建与使用
    SqlServer存储过程的创建与使用
    SqlServer视图的创建与使用
    U盘重装系统:手把手教你怎么使用U盘重装系统、清除登录密码
    附034.Kubernetes_v1.21.0高可用部署架构二
    附032.Kubernetes实现蓝绿发布
    CKS考试心得分享
    001.IT运维面试问题-Linux基础
    附031.Kubernetes_v1.20.4高可用部署架构二
    深入Netty逻辑架构,从Reactor线程模型开始
  • 原文地址:https://www.cnblogs.com/sminocence/p/7281092.html
Copyright © 2020-2023  润新知