promise专题--原生promise基本用法

为什么要用promise?

说到promise就绕不开同步和异步的问题,那么什么是同步什么是异步?
同步就是比如你烧了一壶水,但是此时你想看电视,但是你只能等这壶水烧开了,你才能去看电视,也就是事件是一件完成以后才能去做下一件,这个是同步。

异步就是我再烧水的同时,我也去看电视,当水烧开后发出声音,此时这个声音就相当于个回调函数,告诉我们这个水烧开了,事情做完了,然后我们再去看电视,这个就是异步。

但是当我们异步请求,假如一个需求要请求3个接口,第二个接口参数依赖于第一个的返回值,第三个接口的参数依赖于第二个接口的返回值,那么我们看看常用的ajax异步调用的例子,会出现如下情况:

	$.ajax({
		......
		success(data) {
			$.ajax({
				success(data2) {
					$.ajax({....})
				}
			})
		}
	})

我们会发现,异步处理全部是以回调函数的方式进行的,而且层次感不强,也就是所谓了回调地狱,假如再来个5个回调6个回调,此时就不好维护了,而且剥夺了函数的return的能力,你return了,之后的就不会调用了,所以promise出现就是为了解决这个问题的。


promise的用法

promise有三种状态:

  1. pending: 初始状态,不是成功或失败状态。
  2. fulfilled: 意味着操作成功完成。
  3. rejected: 意味着操作失败。
    这三种状态是不可逆的,而且只能是从等待到成功或者等待到失败,成功了失败是无法相互转换的,同样成功或者失败态也无法到等待态。promise 原生js提供一个类,new Promise() 需要传递一个executor 执行函数,该函数立即执行,默认是等待态调用resolve 为成功态,reject为失败态,then是异步执行。
	let p = new Promise((resolve, reject) => {
    console.log("ok");
   	// resolve("成功了");
    reject("失败了");
	});
	p.then((data) => {
	    console.log(data);
	}, (error) => {
	    console.log(error); // 失败了
	})
	
	let p2 = new Promise((resolve, reject) => {
    console.log("ok");
   	resolve("成功了");
    reject("失败了");
	});
	p2.then((data) => {
	    console.log(data); // 成功了
	}, (error) => {
	    console.log(error); // 不会执行
	})

也就是resolve和reject只会执行一个,谁先执行,之后的就不会执行,也就是上面所说的状态的不可逆。

案例:使用promise处理异步和不使用的对比

	let fs = require("fs")
	// 使用回调
	fs.readFile('./file1',"utf-8", function (err, data) {
    	console.log(data)
	    fs.readFile('./file2',"utf-8", function (err, data) {
	        console.log(data)
	    })
    }// 使用promise
    // 定义读取文件的函数
    function readFile(url) {
    // 返回一个promise实例
	    return new Promise((resolve, reject) => {
	        fs.readFile(url, "utf8", function (err, data) {
	            if (err) {
	                reject(err);
	            } else {
	                resolve(data);
	            }
	        })
	    });
	}
	readFile('./file1').then((data) => {
		    return readFile('./file22')
		}then((data) => {
		    console.log('data', data)
		}, (err) => {
		    console.log('err', err)
	})

这样看来使用promise可以很清晰的看到接口的执行顺序,层次感很强。

一、链式调用返回值的问题

我们都知道promise支持链式调用是因为then之后会返回一个新的promise对象,那么当返回其他值的时候呢?
情况1:当then方法返回一个普通值(数字,字符串,对象)的时候:

	let p = new Promise((resolve, reject) => {
   		resolve("成功了");
	});
	p.then((data) => {
	    console.log(data);
	    return 123;
	}, (error) => {
	    console.log(error); // 失败了
	}).then((data) => {
		console.log(data); // 123
	},(err) => {
		console.log('err2', err)
	}).then((data) => {
		console.log('data2',data); // 打印 undefined
	},(err) => {
		console.log('err3', err)
	})

所以当返回一个普通值的时候,这个值会被传递到下一个then的成功函数中。

情况2:假如返回的不是一个普通值,而是抛出个异常呢?

	let p = new Promise((resolve, reject) => {
   		resolve("成功了");
	});
	p.then((data) => {
	    console.log(data);
	    throw new Error("报错了 无情啊");
	}, (error) => {
	    console.log(error); // 失败了
	}).then((data) => {
		console.log(data); // 123
	},(err) => {
		console.log('err2', err) // 打印错误
	}).then((data) => {
		console.log('data2',data); // 打印 undefined
	},(err) => {
		console.log('err3', err)
	})

所以当扔出一个报错的时候,这个值会被传递到下一个then的失败函数中。
情况3

	let p = new Promise((resolve, reject) => {
   		resolve("成功了");
	});
	p.then((data) => {
	    console.log(data); // 打印成功了
	    return new Promise((resolve, reject) => {
             resolve("成功了,success");
    //         reject("失败了,error")
       })
	}, (error) => {
	    console.log(error); // 如果上一个then执行reject那么这个打印失败了,error
	}).then((data) => {
		console.log(data); // 成功了,success
	},(err) => {
		console.log('err2', err)
	}).then((data) => {
		console.log('data2',data); // 打印 undefined
	},(err) => {
		console.log('err3', err)
	})

所以返回的如果是一个promise 会根据返回的promise是成功还是失败,然后决定返回到成功还是失败,也就是说链式调用,后一个then要看前一个then的返回值,不论它是执行了成功还是失败。

二、错误捕获机制

根据上面的情况2可以知道,如果是抛出一个异常那么会传递到下一个失败中去捕获,那么catch捕获呢?

	let p = new Promise((resolve, reject) => {
   		resolve("成功了");
	});
	// catch就近
	p.then((data) => {
	    console.log(data);
		throw new Error('error')
	}, (error) => {
	    console.log(error); // 失败了
	}).catch(err2 => {
		console.log('catch', err2) // 捕获异常
	}).then((data)=> {
		
	},(err3) => {
		console.log('err3', err3)
	})
	// 失败就近
	p.then((data) => {
	    console.log(data);
		throw new Error('error')
	}, (error) => {
	    console.log(error); // 失败了
	}).then((data)=> {
		
	},(err3) => {
		console.log('err3', err3) // 捕获异常
	}).catch(err2 => {
		console.log('catch', err2) 
	})

所以错误的捕获机制 是找最近的then的失败,以此往下,如果最近有失败捕获,那么catch不会捕获,否则找catch捕获。

三.穿透功能

	let p = new Promise((resolve, reject) => {
	    resolve("7777!");
	});

	// 穿透功能(原生)
	p.then().then().then((data) => {
	    console.log(data) // 打印7777
	},(error)=>{
	    console.log(error)
	})

多个串联then执行,会穿透到最后一个,根据是执行成功或者失败来决定。

四.promise的方法

1.all()

	// 定义一个读取文件的方法
	function readFile(url) {
		// 返回一个promise实例
		return new Promise((resolve, reject) => {
			fs.readFile(url, "utf8", function(err, data) {
				if (err) {
					reject(err);
				} else {
					resolve(data);
				}
			})
		});
	}
	Promise.all([readFile('./file1'), 
		readFile('./file2')]).then((data) => {
		console.log(data)
	}, (err) => {
		console.log(err)
	})

把所有promise实例成功时传都参数 保存在then的成功回调里面,all中只要有一个失败的promise就会执行then的失败回调。

2 race()

	Promise.race([readFile('./file1'), 			
		readFile('./file2')]).then((data) => {
		console.log(data)
	}, (err) => {
		console.log(err)
	})

谁先回来的状态决定then调用成功还是失败,常量最先回来。

3 reject()

	Promise.reject(1111).then((data) => {
		console.log('hello world')
	}, (err) => {
		console.log(err) // 打印111
	})

4 resolve()

返回一个以给定值解析后的Promise 对象

	Promise.resolve(123).then((data) => {
		console.log(data) // 打印123
	}, (err) => {
		console.log(err) 
	})

5 finally()

	Promise.resolve(123).then((data) => {
		console.log(data) // 打印123
	}, (err) => {
		console.log(err) 
	}).finally(() => {
		console.log("完成了")
	})

不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值