Promise学习
Promise
Promise 可以理解成是一个构造函数,接收一个函数作为参数,返回一个 Promise 实例。
状态的改变是通过 resolve() 和 reject() 函数来实现的,可以在异步操作结束后调用这两个函数改变 Promise 实例的状态,它的原型上定义了一个 then 方法,使用这个 then 方法可以为这两个状态的改变注册回调函数。这个回调函数属于微任务,会在本轮事件循环的末尾执行。
注意: 在构造 Promise
的时候,构造函数内部的同步代码是立即执行的。
Promise的基本用法 new Promise((resolve, reject) => { ... })
初始化( new )Promise
首先,初始化一个Promise对象,传入一个函数(后续叫做executor函数),其中两个形参是Promise内部的函数,用来改变这个promise的状态。这两个形参的名称不需要纠结,因为在new一个Promise的过程中,Promise内部会自动将这两个形参作为内部的改变状态用的函数。
executor函数
executor是自行传入的函数,两个形参resolve、reject是用来改变当前promise状态的函数,如果只用到一个也可以只写一个,如果一个都不写应该是就没办法改变这个promise的状态了。
executor函数中可以放入需要异步执行的语句,根据异步执行的结果来判断这个promise后续该为什么状态。
为什么构造promise的时候内部代码是立即执行的?
因为在Promise的函数内部会将实例化时传入的这个函数执行一遍,两个形参resolve 和 reject会在这时通过Promise传入Promise自己的resolve() 和reject()函数。自己传入的函数内的所有同步代码会立即执行,异步代码会根据返回结果调用Promise传入的resolve()和reject()函数,改变这个Promise实例的状态。

1 // promise 封装实现AJAX: 2 function getJSON(url) { 3 // 创建一个 promise 对象 4 let promise = new Promise(function(resolve, reject) { 5 let xhr = new XMLHttpRequest(); 6 // 新建一个 http 请求 7 xhr.open("GET", url, true); 8 // 设置状态的监听函数 9 xhr.onreadystatechange = function() { 10 if (this.readyState !== 4) return; 11 // 当请求成功或失败时,改变 promise 的状态 12 if (this.status === 200) { 13 resolve(this.response); 14 } else { 15 reject(new Error(this.statusText)); 16 } 17 }; 18 // 设置错误监听函数 19 xhr.onerror = function() { 20 reject(new Error(this.statusText)); 21 }; 22 // 设置响应的数据类型 23 xhr.responseType = "json"; 24 // 设置请求头信息 25 xhr.setRequestHeader("Accept", "application/json"); 26 // 发送 http 请求 27 xhr.send(null); 28 }); 29 return promise; 30 }
Promise中的主要元素
callbacks和state
state来保存Promise的状态。
callbacks用来存放Promise执行完毕后的回调函数,因为不能确定传入回调时Promise的状态是否已经改变,所以要用一个空间来存储这些回调,等待异步任务完成后Promise状态改变,统一执行这些函数。
Resolve() Reject()
将当前Promise的状态改变为 fulfilled & rejected,并且根据状态执行callbacks中的回调函数。
除了改变当前Promise状态以及执行then传入的回调函数之外,因为then函数返回的是一个新的Promise,所以还需要在这里处理这个新的Promise。
其他
还有一些静态方法,但是其返回值基本都是一个新的Promise。
then(onResolved(), onRejected())函数
当一个Promise实例的状态发生改变后,执行相应的回调函数,即通过then传入的两个函数。then()函数会返回一个新的Promise,新Promise的状态取决于前一个Promise的状态以及传入的回调函数。这里涉及到了Promise的链式调用。
给一个Promise通过then()添加回调函数有三种情况:
- 当前Promise状态为pending
- 当前Promise状态为resolve
- 当前Promise状态为reject
Promise状态为pending时
此时Promise中的异步操作还没有完成,所以状态还没有改变,但是then已经传入了两个回调函数,所以需要先将这两个回调函数存起来。
因为then的是作为当前Promise的属性调用的,即
LastPromise.then(onResolved, onRejected)
这时then中的this指向的是调用他的Promise,所以会将回调函数存入未完成的Promise中的回调函数数组中。因为一个Promise只有通过调用Promise提供的resolve()和reject()来改变状态,而这两个函数执行时会根据状态的不同执行之前存入的所有回调函数(一个promise可以多次通过then传入回调函数)。
then()返回的是一个新的Promise!!
所以执行完前一个Promise中的回调函数后,还要处理then()返回的新的Promise,并且调用几次then就会有几个新的Promise。这里依然有两种情况:
执行完回调函数后,返回值又是一个Promise
这时实际上已经有了至少四个Promise:
Promise_1--源Promise;
Promise_2--Promise_1.then()返回的Promise,并且由于存在Promise_3的原因,Promise_2的resolve、reject作为Promise_3.then中的回调存进了他的callbacks中;
Promise_3--执行完Promise_1.then()中的回调函数后返回值依然是Promise;
Promise_4--因为Promise_3的存在,Promise_2要等待Promise_3状态改变,由Promise_3.then()生成的Promise,这时会向Promise_3的callbacks中传入Promise_2的resolve&reject,当Promise_3状态确定时将Promise_2的状态一并改变。Promise_4是一个匿名的Promise。
这时Promise_1的状态已经确定,Promise_2的状态为pending,Promise_3的状态为pending,Promise_4的状态为pending。当Promise_3的异步操作完成后,调用Promise_4传入的回调函数,终结Promise_4的状态,Promise_2的resolve或reject被调用,Promise_2的状态随之改变。
一个链式调用的Promise结束。
执行完回调函数后,返回值不是Promise
那么直接调用传入Promise_1的callbacks中Promise_2的resolve&reject终结Promise_2的状态,Promise结束。