一、Promise 特点
- 对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:
- pending: 初始状态,不是成功或失败状态。
- resolve/fulfilled: 意味着操作成功完成。
- rejected: 意味着操作失败。
- 一旦状态改变,就不会再变。
- pendding=>resolve/fulfilled;
- pendding=>rejected;
二、Promise 优缺点
- 优点:
- 链式调用,解决回调地狱问题
- 指定回调函数的方式更加灵活
- 缺点:
- 无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
- 当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
三、主要异步任务
- Ajax请求
- setTimeout定时器
- fs文件流操作等
- …
四、Promise 的简单使用
// fs 异步操作const fs = require('fs');const pro_obj = new Promise((resolve, rejects) => {fs.readFile('./demo.txt', (err, data) => {if (err) rejects(err);resolve(data);});});pro_obj.then((value) => {console.log(value.toString());},(err) => {console.log(err);});
五、 Promise API
- Promise 构造函数: Promise(excutor){}
- executor 函数:执行器 (resolve,reject)=>{}
- resolve 函数:内部定义成功时调用的函数 value=>{}
- reject 函数: 内部定义失败时调用的函数 reson=>{}
注:执行器函数会在Promise内部同步调用,异步操作再执行器中执行
- Promise.prototype.then 方法: (onResolved,onRejected)=>{}
- onResolved 函数: 成功的回调函数 (value)=>{}
- onRejected 函数:失败的回调函数 (reson)=>{}
注:成功或者失败的回调函数返回的是一个新的Promise对象
Promise.prototype.catch方法: (onRejected)=>{}
- onRejected 函数:失败的回调函数 (reson)=>{}
Promise.resolve 方法:(value)=>{}
- value:成功的数据或者Promise对象 (返回一个成功/失败的的Promise对象) ```javascript let p1 = Promise.resolve(521)
// 传入的参数为非Promise类型的对象,则返回的结果是成功的Promise对象
console.log(p1) //Promise { 521 }
// 传入的参数为Promise类型的对象,参数的结果决定了resolve的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => {
resolve(‘ok’)
}))
console.log(p2) // Promise { ‘ok’ }
5. Promise.reject方法:(reson)=>{}1. reson: 返回失败的原因```javascriptlet p1 = Promise.reject(521)console.log(p1) //Promise { <rejected> 521 }let p2 = Promise.reject(new Promise((resolve, reject) => {resolve(521)}))console.log(p2) //Promise { <rejected> Promise { 521 } }// 即使是实例对象的回调函数是成功的,reject返回的还是失败的结果
- Promise.all 方法:(promises)=>{}
- promises:包含n个promise的数组
注:返回一个新的promise,只有所有的promise都成功才算成功,只要一个失败了就直接失败
let p1 = new Promise((resolve, reject) => {resolve('ok');});let p2 = Promise.resolve('success');let p3 = Promise.resolve('okkkk');let p4 = Promise.reject('error');const result = Promise.all([p1, p2, p3]);const err = Promise.all([p1, p2, p3, p4]);console.log(result);console.log(err);
全部成功结果 result:
有一个失败结果 err:
- Promise.race 方法: (promises)=>{}
- promises:包含n个promise的数组
注:返回一个新的promise对象,是第一个成功的的promise的结果状态
let p1 = new Promise((resolve, reject) => {reject('ok');});let p2 = Promise.reject('success');let p3 = Promise.resolve('okkkk');const result = Promise.race([p1, p2, p3]);console.log(result);
六、Promise关键问题
1. 修改Promise状态的方法
- 执行reject方法 pending=> reject
- 执行resolve方法 pending =>resolve
- 丢出错误throw pending=>reject
2.能否执行多个回调
当promise状态改变时,它所定义的多个成功/失败的回调函数都会执行
3.改变promise的状态和指定回调函数谁先谁后(resolve、reject先执行还是then、catch先执行)
- 都有可能,正常情况下是先指定回调再改变状态,但也可以先改变状态再指定回调(看执行器内部的任务队列是同步任务还是异步任务,)
- 如何先改变状态再指定回调
- 在执行器中直接调用resolve或者reject
- 延迟更长时间才调用then()
什么时候拿到数据
简单表达: 由then方法指定的回调函数执行的结果决定
- 详细表达:
7. 中断promise链
当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数。方法:在回调函数中返回一个pendding状态的promise对象
七、手写源码
/*** 1. 搭建Promise基础架构* a.Promise接受executor作为参数传入* b.设置内置属性[PromiseStatus、PromiseResult]和方法[resolve、reject]* Ⅰ. PromiseStatus有三种状态,分别为pending,fulfilled,rejected,状态只能改变一次,pending=>fuifilled pending=>rejected* Ⅱ. PromiseResult 执行的结果保存在PromiseResult中* c. 使用try catch来获取executor中抛出的错误,并返回Promise对象处理抛出的异常* 2. then方法* a. then方法执行回调函数需要有条件,根据状态执行对应的回调函数,函数的实参是存储在PromiseResult的值* b. 处理异步状态,实例对象内部为异步函数,状态是pending ,then方法的回调没有等到pending状态的改变,导致then方法不执行,解决方法:定义callbacks回调数组* 3. 实现catch方法* 4. 实现resolve、reject方法* 5. 实现all、race方法** @param {*} executor*/function Promise(executor) {this.PromiseStatus = 'pending';this.PromiseResult = null;this.callbacks = [];resolve = (data) => {if (this.PromiseStatus !== 'pending') return;this.PromiseResult = data;this.PromiseStatus = 'fulfilled';// 复现原生Promise的异步调用机制setTimeout(() => {this.callbacks.forEach((item) => item.onResolved(data));});};reject = (data) => {if (this.PromiseStatus !== 'pending') return;this.PromiseResult = data;this.PromiseStatus = 'rejected';// 复现原生Promise的异步调用机制setTimeout(() => {this.callbacks.forEach((item) => item.onRejected(data));});};try {executor(resolve, reject);} catch (error) {reject(error);}}Promise.prototype.then = (onResolved, onRejected) => {// 异常穿透if (typeof onResolved !== 'function') {onResolved = (data) => data;}if (typeof onRejected !== 'function') {onRejected = (reason) => {throw reason;};}return new Promise((resolve, reject) => {const callback = (type) => {try {let result = type(this.PromiseResult);if (result instanceof Promise) {result.then((r) => resolve(r),(j) => reject(j));} else {resolve(result);}} catch (error) {reject(error);}};if (this.PromiseStatus === 'fulfilled') {callback(onResolved);}if (this.PromiseStatus === 'rejected') {callback(onRejected);}if (this.PromiseStatus === 'pending') {this.callbacks.push({onResolved: callback(onResolved),onRejected: callback(onRejected),});}});};Promise.prototype.catch = function (onRejected) {return this.then(undefined, onRejected);};Promise.resolve = function (value) {return new Promise((resolve, reject) => {if (value instanceof Promise) {value.then((r) => {resolve(r);},(j) => {reject(j);});} else {resolve(value);}});};Promise.reject = function (value) {return new Promise((resolve, reject) => {reject(value);});};Promise.all = function (pArray) {return new Promise((resolve, reject) => {let count = 0;let pResult = [];for (let i = 0; i < pArray.length; i++) {pArray[i].then((v) => {count++;pResult[i] = v;if (count === pArray.length) {resolve(pResult);}},(j) => {reject(j);});}});};Promise.race = function (pArray) {return new Promise((resolve, reject) => {for (let i = 0; i < pArray.length; i++) {pArray[i].then((r) => {resolve(r);},(j) => {reject(j);});}});};
