前面的一篇说了说Promise的基本用法和常用的方法。知道了Promise的实现原理,我来自己试着谢谢源码
先看看promise是怎么用的
【 例 】
let p = new Promise((resolve,reject)=>{
//同步代码先执行,异步代码先放着,此时是等待状态
console.log('先执行同步的')
setTimeout(() => {
resolve('异步执行成功');
}, 1000);
})
p.then((value)=>{
//成功时
console.log('恭喜',value);//恭喜 成功了
},(reason)=>{
//失败时
console.log('失败了',reason);//失败了 不努力
})
先来实现上面这段代码吧 ,对照上面此代码 写出原生promise 文件:Promise.js,先来说说它的思路吧:
调用resolve时 走成功回调函数,调用reject时 走失败回调函数, resolve 和 reject 这两个函数改变的是promise的状态,只能 从 pending ---->fulfilled 或者 pending---->rejected,不能成功态转为失败态,或者失败态转成功态。在状态改变的同时将结果传递出去,resolve()传递成功的数据,reject() 传递失败的数据。then() 方法接收两个参数,一个是 调resolve时传递成功的值,一个是调用reject时传递的失败的数据。根据已经发生改变的状态决定执行哪个回调
【 超级简洁版 -1 】文件名:Promise.js 。测试这个文件是否正确呢 ,
//定义三种状态
const PENDING = 'PENDING';
const RESOLVE = 'RESOLVE';
const REJECT = 'REJECT';
//Promise是个类
class Promise {
constructor(executor){
//初始状态---静待状态
this.status = PENDING;
this.value = undefined;//记录成功的值
this.reason = undefined;//记录失败的原因
//这是异步的 先执行同步代码,异步的处于等待状态 发布订阅模式--->订报纸,报纸发放到信箱,看报纸时从信箱取出报纸
this.resolveCallbacks = [];//先保存起来,待执行时从数组中取出 相当于信箱
this.rejectCallbacks = []; // 发报纸放到信箱,看报纸时从信箱取出来
let resolve = (value)=>{
if(this.status === PENDING){
this.status = RESOLVE;
this.value = value;
// 发布(收到报纸以后)将来调用成功时将值取出来
this.resolveCallbacks.forEach(fn=>fn(this.value))
}
}
let reject = (reason)=>{
if(this.status === PENDING){
this.status = REJECT;
this.reason = reason;
this.rejectCallbacks.forEach(fn=>fn(this.reason))
}
}
//如果代码出错了就抛出异常,走reject并捕获错误
try{
executor(resolve,reject);
}catch(e){
reject(e);
}
}
//resolve,reject 不是实例上自带的方法 ,是自己定义法的方法
//每个实例都有then方法,是原型上的
then(onfulfilled,onrejected){
if(this.status === RESOLVE){
onfulfilled(this.value)
}
if(this.status === REJECT){
onrejected(this.reason)
}
//等待状态 执行时 可能成功 可能失败
if(this.status === PENDING){
//将成功和失败 回到保存起来 订阅(订报纸)
this.resolveCallbacks.push(onfulfilled);
this.rejectCallbacks.push(onrejected);
}
}
}
//导出
module.exports = Promise;
还是上面的例子,在代码的最上面 引入我们刚刚写的这个文件 let Promise = require('./Promise')
//引入自己写的原生promise.js 文件
let Promise = require('./Promise');
let p = new Promise((resolve,reject)=>{
resolve("成功了");
//reject('不努力');
//throw new Error('出错喽');
})
p.then((value)=>{
//成功时
console.log('恭喜',value);//恭喜 成功了
},(reason)=>{
//失败时
console.log('失败了',reason);//失败了 不努力
})
异步代码(有个模式 叫 发布订阅)
当调用then时 异步代码处于等待状态 还不知道是成功还是失败,先将成功后的执行代码和失败后要执行的代码 保存起来, (相当于订阅)--》订一份报纸 ,放到报箱里,然后在取出来看报纸。当调用resolve的时候,再把它取出来执行
【 简洁版 例 2 】该段的Promise源代码:实现了下面两点逻辑 这个问题可参考我的前一篇文章
1、上一次then的某个回调函数是普通值,会执行下一次then的成功回调(上一次then的某个回调函数是失败态,会返回undefined,则下次的then会走成功态)
2、上一次then的某个回调函数抛异常,会执行下一次then的失败回调
const PENDING = 'PENDING';
const RESOLVE = 'RESOLVE';
const REJECT = 'REJECT';
class Promise{
constructor(executor){
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
//
this.resolveCallBacks = [];
this.rejectCallBacks = [];
let resolve = (value)=>{
if(this.status === PENDING){
this.status = RESOLVE;
this.value = value;
this.resolveCallBacks.forEach(fn=>fn())
}
}
let reject = (reason)=>{
if(this.status === PENDING){
this.status = REJECT;
this.reason = reason;
this.rejectCallBacks.forEach(fn=>fn())
}
}
try{
executor(resolve,reject)
}catch(e){
reject(e)
}
}
then(onfulfilled,onrejected){
let promise02 = new Promise((resolve,reject)=>{
if(this.status === RESOLVE){
try{
let x = onfulfilled(this.value);
resolve(x);
}catch(e){
reject(e)
}
}
if(this.status === REJECT){
try{
let x = onrejected(this.reason);
resolve(x)
}catch(e){
reject(e)
}
}
if(this.status ===PENDING){
this.resolveCallBacks.push(()=>{
try{
let x = onfulfilled(this.value);
resolve(x);
}catch(e){
reject(e)
}
});
this.rejectCallBacks.push(()=>{
try{
let x = onrejected(this.reason);
resolve(x)
}catch(e){
reject(e)
}
});
}
})
return promise02;
}
}
module.exports = Promise;
【 手写源码 例 3 】promise链式调用的原理:返回最新的Promise实例。promise实例可以链式调用,连续调用then,then()返回的是一个新的promise实例。下面的代码实现这个逻辑
const PENDING = 'PENDING';
const RESOLVE = 'RESOLVE';
const REJECT = 'REJECT';
function resolvePromise(promise02,x,resolve,reject){
//如果拿到的x值 和新的promise02相等 就报出错误 (then的返回值跟then本身的调用的返回值一样的话 )
if(x === promise02){
return reject(new TypeError('[aa--Chaining cycle detected for promise #<Promise>]'))
}
let called;//开始没有值
//对x返回值进行判断
if(typeof x === 'object' && x!==null || typeof x === 'function'){
try{
let then = x.then;//取then的时候 可能发生异常
if(typeof then ==='function'){
//x是个promise实例
then.call(x,y => {
//x是成功态的时候
if(called) return;
called = true;
resolvePromise(promise02,y,resolve,reject);
},r=>{
//x是失败态
if(called) return;
called = true;
reject(r);
})//x.then()
}else{
resolve(x);
}
}catch(err){
if(called) return;
called = true;
reject(err);
}
}else{
//不是上述几种情况,那就是个 普通值
resolve(x);
}
}
function isPromise(value){
if(typeof value === 'object' && value !==null || typeof value ==='function'){
if(typeof value.then === 'function'){
return true
}
}
return false;
}
class Promise{
constructor(executor){
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
//当执行异步代码时:不知道结果是失败还是成功,先将成功和失败的逻辑存起来,当异步执行结束后再从这里去处置
this.resolveCallBacks = [];
this.rejectCallBacks = [];
let resolve = (value)=>{
if(value instanceof Promise){
return value.then(resolve,reject)
}//这个if是配合demo-5.js下面一段代码,当value的值是一个实例对象时,让这个value去调then
if(this.status === PENDING){
this.status = RESOLVE;
this.value = value;
this.resolveCallBacks.forEach(fn=>fn())
}
}
let reject = (reason)=>{
if(this.status === PENDING){
this.status = REJECT;
this.reason = reason;
this.rejectCallBacks.forEach(fn=>fn())
}
}
try{
executor(resolve,reject)
}catch(e){
reject(e)
}
}
then(onfulfilled,onrejected){
onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : val => val;
onrejected = typeof onrejected === 'function' ? onrejected : err =>{throw err}
let promise02 = new Promise((resolve,reject)=>{
if(this.status === RESOLVE){
setTimeout(()=>{
try{
let x = onfulfilled(this.value);
//resolve(x); x 是 成功或者失败 的返回值
resolvePromise(promise02,x,resolve,reject)
}catch(e){
reject(e)
}
})
}
if(this.status === REJECT){
setTimeout(()=>{
try{
let x = onrejected(this.reason);
//resolve(x)
resolvePromise(promise02,x,resolve,reject)
}catch(e){
reject(e)
}
})
}
if(this.status ===PENDING){
this.resolveCallBacks.push(()=>{
setTimeout(()=>{
try{
let x = onfulfilled(this.value);
//resolve(x);
resolvePromise(promise02,x,resolve,reject)
}catch(e){
reject(e)
}
})
});
this.rejectCallBacks.push(()=>{
setTimeout(()=>{
try{
let x = onrejected(this.reason);
// resolve(x)
resolvePromise(promise02,x,resolve,reject)
}catch(e){
reject(e)
}
})
});
}
})
return promise02;
}
catch(errCallback){
return this.then(bull,errCallback);
}
static resolve(val){
return new Promise((resolve,reject)=>{
resolve(val);
})
}
static reject(reason){
return new Promise((resolve,reject)=>{
reject(reason);
})
}
//处理并发,前面传递的是个数组,对其进行循环 拿到 数组元素--每个实例
static all(promises){
return new Promise((resolve,reject)=>{
let res = [];
let index = 0;
for (let i = 0; i<promises.length; i++){
let promise = promises[i];
if(isPromise(promise)){
promise.then((y)=>{
res[i] = y;
if(++index === promises.length){
resolve(res);
}
},()=>{
reject;
})
}else{
res[i] = promise;
if(++index === promises.length){
resolve(res);
}
}
}
})
}
}
//根据Promise规范测试此文件是否符合规范 测试
Promise.defer = Promise.deferred = function(){
let dfd = {};
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
//导出模块
module.exports = Promise;
好啦 这一篇先到这里。我的文章都是学习过程中的总结,如果发现错误,欢迎留言指出,我及时更正
本文介绍了Promise的基本使用,并尝试手写Promise的简单源码,探讨了Promise的状态转换、then方法的逻辑以及链式调用的实现原理。通过实例解析,帮助读者深入理解Promise在JavaScript中的异步控制。
5028

被折叠的 条评论
为什么被折叠?



