浅显易懂----Promise(一)

在这里插入图片描述

Promise是什么?

Promise 是异步编程的一种解决方案,Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
—— 阮一峰《ECMAScript 6 入门》

Promise主要解决什么问题?

由于javascript是一门单线程的语言,所以我们早期来处理异步场景的时候,大部分是通过回调函数来进行处理的。

var fn = function(callback){
	setTimeout(function(){
		callback()
	},1000)
}

fn(function(){console.log('hello,萘胺')})

例如上面这个例子,fn函数是一个异步函数,里面执行的setTimeout将会在1s之后调用传入的callback函数,打印出hello,萘胺这个结果。

但是当我们有多个异步操作的时候,就需要有多个异步函数进行嵌套,代码将会变得更加臃肿和难以维护。

setTimeout(function(){
	console.log('执行了')
	setTimeout(function(){
		console.log('再次执行了')
		//.....
	},2000)
},1000)

同样的,还有一个例子:
假设我们有fn1fn2fn3三个异步函数,

var fn1 = function(){
	setTimeout(function(){
		console.log('hellow,小明')
	},1000)
}

var fn2 = function(){
	setTimeout(function(){
		console.log('hellow,小红')
	},3000)
}

var fn3 = function(){
	setTimeout(function(){
		console.log('hellow,小花')
	},2000)
}

我们想顺序对三个函数的结果进行顺序打印,那么使用传统的回调函数来实现的话,我们可以这样写:

var fn1 = function(callback){
	setTimeout(function(){
		console.log('hellow,小明')
		callback()
	},1000)
}

var fn2 = function(callback){
	setTimeout(function(){
		console.log('hellow,小红')
		callback()
	},3000)
}

var fn3 = function(callback){
	setTimeout(function(){
		console.log('hellow,小花')
		callback()
	},2000)
}

fn1(function(){
	fn2(function(){
		fn3(function(){
			console.log('结束了~')
		})
	})
})

//或者

var makefn = function(text,callback,timer){
	setTimeout(function(){
		console.log(text)
		callback()
	},timer)
}

makefn('hellow,小明',function(){
	makefn('hellow,小红',function(){
		makefn('hellow,小花',function(){
			console.log('结束了~')
		},2000)
	},3000)
},1000)

根据上面的例子我们可以看出异步函数之间层层嵌套,形成了回调地狱
回调地狱就是指把函数作为参数层层嵌套请求,我们将其称之为回调地狱,代码阅读性非常差。

Promise基本用法

Promise对象是一个构造函数,用来生成Promise实例

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject

resolve函数
将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数
将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

const person = new Promise((resolve,reject) => {
	let num = 6;
	if(num>5){
		resolve()
	}else{
		reject()
	}
})

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,这两个函数都接受Promise对象传出的值作为参数。

例如:

function promise1(){
	return new Promise((resolve.reject)=>{
		setTimeout(function(){
			console.log('第一次输出')
			resolve()
		},1000)
	})
}

function promise2(){
	return new promise((resolve,reject)=>{
		setTimeout(function(){
			console.log('第二次输出')
			resolve()
		},2000)
	})
}

//我们可以将其写成

promise1.then(function(){return promise2()}) === promise1.then(promise2)

同样,如果promise状态变为了已拒绝状态,也就是执行了reject方法,那么就会进入到后续的异常处理函数中。

function promise3(){
	return new Promise((resolve,reject)=>{
		let num = Math.random() * 10;
		if(num > 4){
			resolve(num)
		}else{
			reject(num)
		}
	})
}

let onReolved = function(num){
	console.log('成功了~,数字是:',num)
}

let onRejected = function(num){
	console.log('失败了~,数字是:',num)
}

//通过.then()方法的第二个参数来进行捕获异常
promise3().then(onReolved,onRejected)

//promise又一个.catch()方法,可以对异常进行捕获
promise3().catch(onRejected).then(onReolved)

//通过try catch来进行拦截状态变为reject的promise
try{
	promise3().then(onReolved)
}catch(e){
	onRejected(e)
}

在改变promise状态调用resolvereject的时候,我们还可以给下一步.then()函数只执行的方法进行传递参数。

总结:

  1. promise会有三种状态,进行中(pedding),已完成(onFulfilled)和已拒绝(onRejected),状态被更改后无法继续更改。
  2. promise构造函数接收两个参数resolvereject),执行第一个参数后会改变当前promise为已完成状态,执行第二个参数后会变为已拒绝状态。
  3. 通过.then方法,即可在上一个promise变为已完成状态时继续执行下一函数或者promise。同时通过resolve或者reject传入参数,可以给下一个promise或函数传入初始值。
  4. 已拒绝状态的promise,可以通过.catch方法或.then方法的第二个参数或try catch方法进行异常捕获。

如何将异步操作封装为promise?

例如我们将文章开头的顺序打印三个异步函数进行改造:

var fn = function(text,timer){
	return new Promise((resolve)=>{
		setTimeout(function(){
			console.log(text)
			resolve()
		},timer)
	})
	
}

//改造后

fn('hello,小明'1000).then(function(){
	return fn('hello,小红',3000)
})
.then(function(){
	return fn('hello,小花',2000)
})
.then(function(){
	console.log('结束了~')
})

我们还可以对ajax请求进行封装:

function ajax(url,success,fail){
	var client = new XMLHttpRequest();
	client.open("GET",url);
	client.onreadystatechange = function(){
		if(this.readyState !== 4){
			return
		}
		if(this.status === 200){
			success(this.respones)
		}else{
			fail(new Error(this.statusText))
		}
	}
	client.send()
}

ajax('/ajax.json',function(){
	console.log('成功~')
},function(){
	console.log('失败了~')
})

//将其改造成promise

function ajax(url){
	return new Promise((resolve,reject)=>{
		var client = new XMLHttpRequest();
		client.open("GET",url);
		client.onreadystatechange = function(){
			if(this.readyState !== 4){
				return
			}
			if(this.status === 200){
				resolve(this.respones)
			}else{
				reject(new Error(this.statusText))
			}
		}
		client.send()
	})
}

ajax('/ajax.json')
.catch(function(){
	console.log('失败了~')
}).then(function(){
	console.log('成功了~')
})

注意1:

var p1 = new Promise(function(resolve,reject){
	//.....
})

var p2 = new Promise(function(resolve,reject){
	//....
	resolve(p1)
})

如果将p2的resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作。

这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。

注意2:

new Promise((resolve,reject)=>{
	resolve(1)
	console.log('2')
}).then(function(num){
	console.log(num)
})
//2
//1
//resolve()之后的语句仍然会执行

所以为了避免不必要的错误,最好是在resolve或者reject的时候加上return语句。

new Promise((resolve,reject)=>{
	return resolve(1)
	console.log('2')  //后面的语句不会向下执行
}).then(function(num){
	console.log(num)

Promise.then()

then方法是定义在Promise原型对象上。

then方法的第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数。

then方法返回的是一个新的Promise实例。

getdata(url).then(function(data) {
  return data.list;
}).then(function(data) {
  // console.log(data)
});

使用then方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。

采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。

getdata(first_url).then(
  post => getdata(second_url)
).then(
  data => console.log("resolved: ", data),
  err => console.log("rejected: ", err)
);

第一个then方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。如果变为resolved,就调用第一个回调函数,如果状态变为rejected,就调用第二个回调函数。

本文参考:

ECMAScript 6 入门
其他

To be continued…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值