Promise学习

前期准备

实例对象与函数对象

  • 实例对象:new 函数产生的对象,称为实例对象,简称为对象
  • 函数对象:将函数作为对象使用时,称为函数对象
  • 函数对象.实例对象
function Fn() {}   //Fn为函数
const fn = new Fn()  //Fn称为构造函数,fn为实例对象
console.log(Fn.prototype) //Fn作为对象使用时,称为函数对象
Fn.bind({})  //Fn作为函数对象使用
$('#test')  //$作为函数使用
$.get('/test')  //$作为函数对象使用

同步回调与异步回调

同步回调

  • 立即执行,完全执行完了才结束,不会放入回调队列中
  • 数组遍历相关的回调 / Promise的executor函数
const arr = [1, 3, 5];
//遍历回调,同步回调,不放入队列,立即执行
arr.forEach(item => {  
	console.log(item);
})  //1 3 5

异步回调

  • 不立即执行,放入回调队列中执行、
  • 定时器回调 / ajax回调 / Promise成功或失败的回调
//定时器回调
setTimeout(() => {
	console.log(1)
}, 0)
console.log(2)   //2 1
// Promise 成功或失败的回调
new Promise((resolve, reject) => {
	resolve(1)
}).then(
	value => {console.log('value', value)},
	reason => {console.log('reason', reason)}
)
console.log(2)
//2
//value 1

JS中的异常error处理

错误的类型

  • Error:所有错误的父类型
  • ReferenceError:引用的变量不存在
  • TypeError:数据类型不正确
  • RangeError:数据值不在其所允许的范围内
  • SyntaxError:语法错误

错误处理(捕获与抛出)

  • 抛出错误:throw error
function something() {
	if (Date.now()%2===1) {
    	console.log('当前时间为奇数,可以执行任务')
	} else { //如果时间为偶数抛出异常,由调用来处理
    	throw new Error('当前时间为偶数,无法执行任务')
	}
}
  • 捕获错误:try … catch
try {
	something()
} catch (error) {
	alert(error.message)
}

错误对象

  • message属性:错误相关信息
  • stack属性:函数调用栈记录信息
try {
	let d
	console.log(d.xx)
} catch (error) {
	console.log(error.message)
	console.log(error.stack)
}
console.log('已出错')
// Cannot read property 'xx' of undefined
// TypeError:Cannot read property 'xx' of undefined
// 已出错
// 因为错误被捕获处理了,后面的代码才能运行下去,打印出’已出错‘

Promise的理解与使用

Promise是什么

理解

  • 抽象表达:Promise是JS中进行异步编程的新的解决方案(旧方案是单纯使用回调函数)
  • 具体表达:
    ①从语法上看:Promise是一个构造函数 (自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法)
    ②从功能上看:promise对象用来封装一个异步操作并可以获取其成功/失败的结果值

状态

  • 实例对象promise中的一个属性 PromiseState
    1.pending 变为 resolved/fullfilled
    2.pending 变为 rejected
  • 对象的状态不受外界影响
  • 只有这两种,且一个 promise 对象只能改变一次
  • 一旦状态改变,就不会再变,任何时候都可以得到这个结果
  • 无论成功还是失败,都会有一个结果数据。成功的结果数据一般称为 value,而失败的一般称为 reason

  • 实例对象promise的另一个值 PromiseResult
  • 保存着对象 成功/失败 的值(value/reason)
  • resolve/reject可以修改值

基本流程在这里插入图片描述

基本使用

  • Promise构造函数接受一个函数(执行器函数)作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
  • resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数value传递出去
  • reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数error/reason传递出去
  • Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数
  • then方法可以接受两个回调函数作为参数:
    第一个回调函数onResolved()是Promise对象的状态变为resolved时调用
    第二个回调函数onRejected()是Promise对象的状态变为rejected时调用
    都接受Promise对象传出的值作为参数

为什么用Promise

指定回调函数的方式更加灵活

promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(甚至可以在异步任务结束后指定)

支持链式调用,可以解决回调地狱问题

  • 回调地狱:回调函数嵌套调用,外部回调函数异步执行的结果是其内部嵌套的回调函数执行的条件
  • 解决方案:promise链式调用
doSomething()
  .then(result => doSomethingElse(result))
  .then(newResult => doThirdThing(newResult))
  .then(finalResult => {console.log('Got the final result:' + finalResult)})
  .catch(failureCallback)
  • 终极解决方案async/await
async function request() {
  try{
    const result = await doSomething()
    const newResult = await doSomethingElse(result)
    const finalResult = await doThirdThing(newResult)
    console.log('Got the final result:' + finalResult)
  } catch (error) {
    failureCallback(error)
  }
}

如何使用Promise

Promise构造函数

Promise (excutor){}

  • executor函数:执行器 (resolve, reject) => {}
  • resolve函数:内部定义成功时调用的函数 resove(value)
  • reject 函数:内部定义失败时调用的函数 reject(reason)
  • NOTE:executor 是执行器,会在 Promise 内部立即同步回调,异步操作 resolve/reject 就在 executor 中执行

Promise.prototype.then方法

p.then(onResolved, onRejected) => {}

  • onResolved 函数:成功的回调函数 (value) => {}
  • onRejected 函数:失败的回调函数 (reason) => {}
  • NOTE:指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调,返回一个新的 promise 对象

Promise.prototype.catch方法

p.catch(onRejected) => {}

  • onRejected 函数:失败的回调函数 (reason) => {}
  • 相当于then(undefined, onRejected)
new Promise((resolve, reject) => { // excutor执行器函数
	setTimeout(() => {
		if(...) {
			resolve('成功的数据') // resolve()函数
		} else { 
			reject('失败的数据') //reject()函数
		}
	}, 1000)
}).then(
	value => { // onResolved()函数
		console.log(value) // 成功的数据
	}
).catch(
	reason => { // onRejected()函数
		console.log(reason) // 失败的数据
	}
)

Promise.resolve 方法

Promise.resolve(value)

  • value:将被 Promise 对象解析的参数,也可以是一个成功或失败的 Promise 对象
  • 返回:返回一个带着给定值解析过的 Promise 对象,如果参数本身就是一个 Promise 对象,则直接返回这个 Promise 对象
  • 1.如果传入的参数为 非Promise类型的对象, 则返回的结果为成功promise对象
let p1 = Promise.resolve(520);
console.log(p1);  // Promise {<fulfilled>: 521}
  • 2.如果传入的参数为 Promise 对象, 则参数的结果决定了 resolve 的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => {
	resolve('OK')  //成功的Promise
	reject('Error');
}));
console.log(p2);
p2.catch(reason => {
	console.log(reason);
})   //Error

Promise.reject 方法

Promise.reject(reason)

  • reason:失败的原因
  • 说明:返回一个失败的 promise 对象

Promise.all方法

Promise.all(iterable)

  • iterable:包含 n 个 promise 的可迭代对象,如 Array 或 String
  • 说明:返回一个新的 promise,只有所有的 promise 都成功才成功,只要有一个失败了就直接失败

Promise.race方法

Promise.race(iterable)

  • 说明:返回一个新的 promise,第一个完成的 promise 的结果状态就是最终的结果状态;谁先完成就输出谁(不管是成功还是失败)

关键问题

如何改变 promise 的状态

  • resolve(value):如果当前是 pending 就会变为 resolved
  • reject(reason):如果当前是 pending 就会变为 rejected
  • 抛出异常:如果当前是 pending 就会变为 rejected
let p = new Promise((resolve, reject) => {
	resolve(1); //pending => fulfilled(resolved)
	reject(2); //pending => rejected
	throw '出问题了';  // 抛出异常,promise变为rejected失败状态,reason为抛出的error
})

能否执行多个回调

当 promise 改变为对应状态时都会调用

let p = new Promise((resolve, reject) => {
	reject(77)
});
p.then(
	value => {}
	reason => {console.log('reason', reason)}
)
p.then(
	value => {}
	reason => {console.log('reason2', reason)}
)
// reason 77
// reason2 77

改变 promise 状态和指定回调函数谁先谁后

都有可能,常规是先指定回调再改变状态,但也可以先改状态再指定回调

  • 先改状态再指定回调
    1.在执行器中直接调用 resolve()/reject()
    2.延迟更长时间才调用 then()
let p = new Promise((resolve, reject) => {
	// setTimeout(() => {
		resolve('OK');
	// }, 1000); // 有异步就先指定回调,否则先改变状态
});
p.then(value => {
  console.log(value);
},reason => {}
)
  • 什么时候才能得到数据
    1.如果先指定的回调,那当状态发生改变时,回调函数就会调用得到数据
    2.如果先改变的状态,那当指定回调时,回调函数就会调用得到数据

promise.then() 返回的新 promise 的结果状态

  • 简单表达:由 then() 指定的回调函数执行的结果决定
let p = new Promise((resolve, reject) => {
	resolve('ok');
});
let result = p.then(value => {
	console.log(value);
}, reason => {
	console.log(reason);
});
console.log(result);
  • 如果抛出异常,新 promise 变为 rejected,reason 为抛出的异常
let p = new Promise((resolve, reject) => {
	resolve('ok');
});
let result = p.then(value => {
	throw '错误';
}, reason => {
	console.log(reason);
});
console.log(result);
  • 如果返回的是非 promise 的任意值,新 promise 变为 resolved,value 为返回的值
let p = new Promise((resolve, reject) => {
	resolve('ok');
});
let result = p.then(value => {
	return 777;
}, reason => {
	console.log(reason);
});
console.log(result);
  • 如果返回的是另一个新 promise,此 promise 的结果就会成为新 promise 的结果
let p = new Promise((resolve, reject) => {
	resolve('ok');
});
let result = p.then(value => {
	return new Promis((resolve, reject) => {
		reject('error');
	});
}, reason => {
	console.log(reason);
});
console.log(result);

串联多个任务

  • promise 的 then() 返回一个新的 promise,可以并成 then() 的链式调用
  • 通过 then 的链式调用串联多个同步/异步任务
let p = new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve('OK');
	}, 1000);
});
p.then(value => {
	return new Promise((resolve, reject) => {
		resolve("success");
	});
}).then(value => {
	console.log(value); // success
}).then(value => {
	console.log(value); // undefined
})

异常穿透

  • 当使用 promise 的 then 链式调用时,可以在最后指定失败的回调
  • 前面任何操作出了异常,都会传到最后失败的回调中处理
new Promise((resolve, reject) => {
	//resolve(1)
	reject(1)
}).then(
	value => {
		console.log('onResolved1()', value)
		return 2
	}
).then(
	value => {
    	console.log('onResolved2()', value)
    	return 3
	}
).then(
	value => {
    	console.log('onResolved3()', value)
	}
).catch(
	reason => {
    	console.log('onRejected1()', reason)
	}
)
// onRejected1() 1

如何中断Promise

  • 当使用 promise 的 then 链式调用时,在中间中断,不再调用后面的回调函数
  • 办法:在回调函数中返回一个 pending 状态的 promise 对象 return new Promise(() => {});

自定义(手写)Promise

整体结构框架

//声明构造函数
function Promise(executer) {
    //保存当前实例对象的this的值
    const self = this;
    //添加属性
    // 给promise对象指定status属性,初始值为pending
    self.PromiseState = PENDING;
    //给promise对象指定一个用于存储结果数据的属性
    self.PromiseResult = null;
    // 存的是对象 每个元素的结构:{onResolved() {}, onRejected() {}}
    self.callbacks = [];

    //resolve函数
    function resolve(value) {
        //判断状态
        if (self.PromiseState !== PENDING) return;
        //1.修改对象状态(promiseState)
        self.PromiseState = RESOLVED;  //resolved
        //2.设置对象结果值(promiseResult)
        self.PromiseResult = value;
        // 如果有待执行的callback函数,立即【异步】执行回调函数onResolved
        if (self.callbacks.length > 0) {
            setTimeout(() => {
                self.callbacks.forEach(callbackObj => {
                    callbackObj.onResolved(value);
                })
            }, 0);
        }
    }

    //reject函数
    function reject(reason) {
        //判断状态
        if (self.PromiseState !== PENDING) return;
        //1.修改对象状态(promiseState)
        self.PromiseState = REJECTED;
        //2.设置对象结果值(promiseResult)
        self.PromiseResult = reason;
        // 如果有待执行的callback函数,立即【异步】执行回调函数onResolved
        if (self.callbacks.length > 0) {
            setTimeout(() => {
                self.callbacks.forEach(callbackObj => {
                    callbackObj.onRejected(reason);
                })
            }, 0);
        }
    }

    try {
        //同步调用 执行器函数
        executer(resolve, reject);
    } catch (error) {
        //修改promise对象状态为失败
        reject(error);
    }
}

Promise.prototype.then

//添加then方法
Promise.prototype.then = function (onResolved, onRejected) {
    //指定默认的成功的回调onResolved (向后传递成功的value)
    onResolved = typeof onResolved === 'function' ? onResolved : value => value
    // 指定默认的失败的回调onRejected(向后传递失败的reason 实现错误/异常传透的关键点)
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }

    const self = this
    return new Promise((resolve, reject) => {
        function handle(callback) {
            try {
                // result获取回调函数执行(return)的结果
                const result = callback(self.PromiseResult);
                if (result instanceof Promise) {
                    result.then(resolve, reject);
                } else {
                    resolve(result);
                }
            } catch (error) {
                reject(error);
            }
        }
        //判断pending状态
        if (this.PromiseState === PENDING) {
            self.callbacks.push({
                onResolved(value) {
                    handle(onResolved);
                },
                onRejected(reason) {
                    handle(onRejected);
                }
            })
        } else if (self.PromiseState === RESOLVED) {
            setTimeout(() => {
                handle(onResolved)
            }, 0)
        } else {
            setTimeout(() => {
                handle(onRejected)
            }, 0)
        }
    })
}

Promise.prototype.catch

//添加catch方法
Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected);
}

Promise.resolve

//添加resolve方法
Promise.resolve = function (value) {
    return new Promise((resolve, reject) => {
        if (value instanceof Promise) {
            value.then(resolve, reject);
        } else {
            resolve(value);
        }
    })
}

Promise.reject

//添加reject方法
Promise.reject = function (reason) {
    return new Promise((resolve, reject) => {
        reject(reason);
    })
}

Promise.all

//添加all方法
Promise.all = function (promises) {
    return new Promise((resolve, reject) => {
        //声明计数变量
        let count = 0;
        const values = new Array(promises.length);
        for (let i = 0; i < promises.length; i++) {
            // 防止数组中有不是promise的元素
            Promise.resolve(promises[i]).then(value => {
                //对象状态成功+1
                count++;
                //将当前promise对象成功的结果存入数组
                values[i] = value;
                //如果每个promise对象都成功
                if (count === promises.length) {
                    resolve(values);
                }
            }, reason => {
                reject(reason);
            })
        }
    })
}

Promise.race

	//添加race方法
	static resolveDelay(value, timeout) {
		// 延时返回一个成功/失败的promise
		return new Promise((resolve, reject) => {
			setTimeout(() => {
            	if (value instanceof Promise) {
                	value.then(resolve, reject)
                } else { // value不是promise => promise状态变为成功,数据是value
                    resolve(value)
                }
            })
        }, timeout);
   }
   static rejectDelay(reason, timeout) {
   		// 延时返回一个失败的promise
        return new Promise((resolve, reject) => {
        	setTimeout(() => {
            	reject(reason)
            }, timeout)
        })
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值