一、promise和Ajax的串行并行

1.什么是promise?

ES6 语法规范中新增加的内置类,用来处理 JS 中异步编程的,而我们所谓的 promise 设计模式,就是基于 promise 对异步操作进行管理

2.异步编程中的“回调地狱”
  • AJAX 的串行

AJAX 的串行:只有第一个请求成功才能执行第二个,第二个成功才能执行第三个…最后一个请求成功后拿到了每一次请求的所有数据

$.ajax({
	url:'/baseInfo',
	method:'GET',
	data:{
		name:'zhanglu'
	},
	success:result=>{
		let scoreId=result.scoreId;

		$.ajax({
			url:'/scoreInfo',
			method:'GET',
			data:{
				id:scoreId
			},
			success:result=>{
				let chinese=result.chinese;

				$.ajax({
					url:'/paiming',
					method:'GET',
					data:{
						num:chinese
					},
					success:result=>{


					}
				});
			}
		});
	}
});
  • AJAX 的并行

AJAX 的并行:三个请求可以同时发送,但是需要等到所有请求都成功才会做一件事

let chi=100,
	eng=12,
	math=98;
let chiPai,
	engPai,
	mathPai;
let count=0;
function func(){
	if(count>=3){
		//=>处理自己要做的事情
	}
}

$.ajax({
	url:'/pai?chi='+chi,
	success:result=>{
		chiPai=result;
		count++;
		func();
	}
});
$.ajax({
	url:'/pai?eng='+eng,
	success:result=>{
		engPai=result;
		count++;
		func();
	}
});
$.ajax({
	url:'/pai?math='+math,
	success:result=>{
		mathPai=result;
		count++;
		func();
	}
});

二、promise基础知识1:executor和promise状态

// let promiseExamp = new Promise(); //=>Uncaught TypeError: Promise resolver undefined is not a function

/*
 * new Promise([executor]):第一个执行函数必须传递
 *   [executor 简称EXE]
 *     1.NEW PROMISE的时候就会把EXE执行,创建PROMISE的一个实例(EXE是PROMISE类的一个回调函数,PROMISE内部会把它执行)
 *     2.PROMISE不仅把EXE执行,而且还给EXE传递两个参数(两个参数也是函数类型):
 * 		 =>resolve函数:它执行代表PROMISE处理的异步事情是成功的,把PROMISE的状态改为fulfilled/resolved
 *       =>reject函数:它执行代表PROMISE处理的异步事情是失败的,把PROMISE的状态改为rejected
 *     3.EXE函数中放的就是当前要处理的异步操作事情
 */
let pro = new Promise((resolve, reject) => {
	//=>这里一般存放的都是我们即将要处理的异步任务,任务成功我们执行resolve,任务失败我们执行reject(当然写同步的也可以)
	setTimeout(() => {
		if (Math.random() < 0.5) {
			reject('呵呵');
			return;
		}
		resolve('哈哈');
	}, 1000);
});

在这里插入图片描述

三、promise基础知识2:then、catch、finally

1.Promise.prototype.then

then:设置成功或者失败后执行的方法(成功或者失败都可以设置,也可以只设置一个)

  • pro.then([success],[error])
  • pro.then([success])
  • pro.then(null,[error])
let pro = new Promise((resolve, reject) => {
	//=>这里一般存放的都是我们即将要处理的异步任务,任务成功我们执行resolve,任务失败我们执行reject(当然写同步的也可以)
	setTimeout(() => {
		if (Math.random() < 0.5) {
			reject('呵呵');
			return;
		}
		resolve('哈哈');
	}, 1000);
});
pro.then(result => {
	//=>状态为fulfilled成功后执行(RESULT:[[PromiseValue]])
	console.log('成功: ' + result);
}, error => {
	//=>状态为rejected失败后执行
	console.log('失败: ' + error);
});

在这里插入图片描述

2.Promise.prototype.catch、Promise.prototype.finally
  • catch:设置失败后执行的方法(只处理状态为失败下做的事情)
  • finally:设置不论成功还是失败都会执行的方法(一般不用)
let promiseExamp = new Promise((resolve, reject) => {
	setTimeout(() => {
		let ran = Math.random();
		ran < 0.5 ? reject(ran) : resolve(ran);
	}, 1000);
});
promiseExamp.then(result => {
	console.log('成功: ' + result);
});
promiseExamp.catch(error => {
	console.log('失败: ' + error);
});
promiseExamp.finally(x => {
	console.log('哈哈');
});

【扩展知识】:try{ } catch( ){ }

/* console.log(a); //=>Uncaught ReferenceError: a is not defined
let b = 10;
console.log(b); */

//=>在JS中当前行代码报错,会中断主线程的渲染(下面代码将不再执行)
// throw new Error(''):手动抛出一个异常错误,目的就是让后面代码不再执行
// 如果上面代码报错,不想让期影响后面的代码,我们需要做异常捕获:try catch finally

try {
	console.log(a);
} catch (e) {
	//=>错误信息
	// console.log(e.message);
}
let b = 10;
console.log(b); 

四、promise基础知识3:then链

//=>then(onResolve,onReject)
//执行THEN/CATCH/FINALLY返回的结果是一个全新的PROMISE实例,所以可以链式写下去;下一个THEN中哪个方式会被执行,由上一个THEN中某个方法执行的结果来决定
//上一个THEN中某个方法的返回值会传递给下一个THEN的某个方法中
/* new Promise((resolve, reject) => {
	// resolve(100); //=>把第一个PROMISE实例的VALUE值改为100/-100
	reject(-100);
}).then(result => {
	console.log(result);
	return result * 10; //=>THEN中RETURN的结果相当于把当前这个新的PROMISE实例中的VALUE值改为返回值
}, err => {
	console.log(err);
	return err / 10;
}).then(A => {
	console.log('A:' + A);
}, B => {
	console.log('B:' + B);
}).then(C => {

}, D => {

}); */

//如果当前PROMISE实例的状态确定后,都会到对应的THEN中找方法,如果THEN中没有对应的这个方法,则会向下顺延
//THEN(onFulfilled)  THEN(null,onRejected)  
/* new Promise((resolve, reject) => {
	reject(-100);
}).then(A => {
	console.log(A);
	return A * 10;
}).catch(B => {
	console.log(B); //=>-100
	return B * 10;
}); */

/* new Promise((resolve, reject) => {
	resolve(100);
}).then(A => {
	console.log(AAAAA); //=>执行报错,让.THEN创建的PROMISE实例变为失败状态,并且把报错的原因修改此PROMISE的VALUE值
	return A * 10;
}).catch(B => {
	console.log(B); //=>ReferenceError: AAAAA is not defined
	return '@';
}).then(C => {
	console.log(C); //=>'@'
}); */

/* new Promise((resolve, reject) => {
	resolve();
}).then().catch(x => {
	console.log(1);
}).then(x => {
	console.log(2); //=>OK
}).then(x => {
	console.log(3); //=>OK
}).catch(x => {
	console.log(4);
}).then(x => {
	console.log('AAA'); //=>OK
	console.log(AAA); //=>报错
}).catch().then(null, x => {
	console.log(5); //=>OK
}); */

/* let pro1 = new Promise((resolve, reject) => {
	setTimeout(() => {
		let ran = Math.random();
		ran < 0.5 ? reject(ran) : resolve(ran);
	}, 1000);
});

let pro2 = pro1.then(result => {
	console.log(`PRO1:SUCCESS`);
}, error => {
	console.log(`PRO1:ERROR`)
});

let pro3 = pro2.then(result => {
	console.log(`PRO1:SUCCESS`);
}, error => {
	console.log(`PRO1:ERROR`)
}); */

五、promise的应用:解决Ajax中的串行并行

<!-- 解决AJAX回调地狱 -->
<script>
	function queryBase() {
		return new Promise(resolve => {
			$.ajax({
				url: '/baseInfo?name=zhanglu',
				success: result => {
					resolve(result);
				}
			});
		});
	}

	function queryScore(scoreId) {
		return new Promise(resolve => {
			$.ajax({
				url: '/score?id=' + scoreId,
				success: result => {
					resolve(result);
				}
			});
		});
	}

	function queryChinese(chinese) {
		return new Promise(resolve => {
			$.ajax({
				url: '/paiming?chin=' + chinese,
				success: result => {
					resolve(result);
				}
			});
		});
	}

	/* queryBase().then(baseInfo => {
		let scoreId = baseInfo.scoreId;
		//=>THEN方法中如果返回的是一个PROMISE实例,则当前返回实例的成功或者失败状态,影响着下一个THEN中哪个方法会被触发执行;如果返回的是非PROMISE实例,则看当前方法执行是否报错,来决定下一个THEN中哪个方法执行;
		return queryScore(scoreId);
	}).then(scoreInfo => {
		let chinese = scoreInfo.chinese;
		return queryChinese(chinese);
	}).then(pai => {
		console.log('排名是:' + pai);
	}); */

	/* queryBase().then(baseInfo => queryScore(baseInfo.scoreId))
		.then(scoreInfo => queryChinese(scoreInfo.chinese))
		.then(pai => {
			console.log('排名是:' + pai);
		}); */

	/* async function func() {
		let baseInfo = await queryBase();
		let scoreInfo = await queryScore(baseInfo.scoreId);
		let pai = await queryChinese(scoreInfo.chinese);
		//....
	}
	func(); */
</script>

<!-- 解决AJAX并行 -->
<script>
	function ajax1() {
		return new Promise(resolve => {
			$.ajax({
				url: '/api1',
				success: resolve
			});
		});
	}

	function ajax2() {
		return new Promise(resolve => {
			$.ajax({
				url: '/api2',
				success: resolve
			});
		});
	}

	function ajax3() {
		return new Promise(resolve => {
			$.ajax({
				url: '/api3',
				success: resolve
			});
		});
	}

	// Promise.all([promise1,promise2,...]):ALL中存放的是多个PROMISE实例(每一个实例管理者一个异步操作),执行ALL方法返回的结果是一个新的PROMISE实例"PROA"
	//=>当所有PROMISE实例的状态都为Fulfilled的时候(成功),让PROA的状态也变为Fulfilled,并且把所有PROMISE成功获取的结果,存储为成为一个数组(顺序和最开始编写的顺序一致)“result=[result1,result2,...]”,让PROA这个数组的VALUE值等于这个数组
	//=>都成功(PROA状态是FUFILLED)才会通知THEN中第一个方法执行,只要有一个失败(PROA状态是REJECTED),就会通知THEN中第二个方法或者CATCH中的方法执行
	Promise.all([ajax1(), ajax3(), ajax2()]).then(results => {
		//=>results:[result1,result3,result2]
	});

	Promise.race([ajax1(), ajax3(), ajax2()]).then(result => {
		//=>看哪一个PROMISE状态最先处理完(成功或者失败),以最先处理完的为主
	});
</script>

六、axios的基础语法

<!-- IMPORT JS -->
<script src="node_modules/axios/dist/axios.min.js"></script>
<script>
	/*
	 * axios:一款基于PROMISE设计模式封装的AJAX库(JQ中的AJAX就是最普通的AJAX库,没有基于PROMISE管理) 
	 */
	//=>axios.get([URL],[OPTIONS]);
	// axios.get();
	// axios.delete();
	// axios.head();

	//=>axios.post([URL],[DATA],[OPTIONS]):DATA通过请求主体传递给服务器的内容
	// axios.post();
	// axios.put();

	/*
	 * OPTIONS
	 *   baseURL:基础的URL路径 
	 *   transformRequest:处理请求参数(对POST系列有作用)
	 *   transformResponse:把返回的结果进行处理
	 *   headers:设置请求头
	 *   params:GET系列请求传递给服务器的内容(会把PARAMS中的内容拼接为X-WWW-FORM-URLENCODED这种格式,基于URL问号传参传递给服务器)
	 *   paramsSerializer:传递参数的序列化
	 *   timeout:超时时间
	 *   withCredentials:跨域请求中是否允许携带凭证
	 *   responseType:预设服务器返回结果的格式,默认是JSON,支持BUFFER/TEXT/STREAM/DOCUMENT...
	 *   validateStatus:AXIOS本身只有在HTTP状态码以2开头的时候才认为是成功,其余都认为是失败状态,当然我们可以自己来设置,基于validateStatus这个来修改
	 *   ......
	 */


	//=>执行axios.xxx()都会返回一个PROMISE实例,AJAX请求成功会把实例的状态改为FULFILLED/RESOLVED,请求失败状态改为REJECTED;并且获取的结果或者错误原因作为PROMISE的VALUE
	/* axios.get('http://127.0.0.1:5500/json/data2.json', {
		headers: {
			AAA: encodeURIComponent('珠峰哈哈哈')
		},
		params: {
			lx: 1,
			from: 'WX'
		}
	}).then(result => {
		//=>result:从服务器获取的结果
		/!*
		 * CONFIG:我们自己配置的选项信息
		 * DATA:存储的是响应主体内容 
		 * HEADERS:存储响应头的信息
		 * REQUEST:AJAX实例
		 * STATUS:响应状态码
		 * STATUS-TEXT:状态码的描述
		 *!/
		return result.data;
	}).catch(reason => {
		console.log(reason);
		throw new Error(reason);
	}).then(data => {
		//=>data:从服务器获取的响应主体内容
		console.log(data);
	}); */
</script>

<script>
	axios.post('http://127.0.0.1:5500/json/data2.json', {
		lx: 1,
		from: 'WX'
	}, {
		headers: {
			AAA: encodeURIComponent('珠峰哈哈哈')
		},
		transformRequest: function (data) {
			if (!data) return data;
			let str = ``;
			for (let key in data) {
				if (!data.hasOwnProperty(key)) break;
				str += `&${key}=${data[key]}`;
			}
			return str.substring(1);
		}
	}).then(result => {
		return result.data;
	}).catch(reason => {
		throw new Error(reason);
	}).then(data => {
		console.log(data);
	});
</script>

七、axios的默认参数配置和拦截器

<script>
	/* 在使用AXIOS之前,我们一般都需要配置默认的配置项 */
	// 1.基础URL,后期再发送请求的时候,URL请求地址最前面的公共部分就不需要再写了
	axios.defaults.baseURL = "http://127.0.0.1:5500";
	// 2.跨域请求中允许携带资源凭证(例如COOKIE信息)
	axios.defaults.withCredentials = true;
	// 3.设置请求头:POST系列中,我们传递给服务器数据的格式一般以x-www-form-urlencoded格式为主
	axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';
	// 4.设置请求拦截器(只对POST系列有用):把基于请求主体传递给服务器的内容进行拦截,把内容格式变为x-www-form-urlencoded这种格式,再传递给服务器
	axios.defaults.transformRequest = function (data) {
		if (!data) return data;
		let str = ``;
		for (let key in data) {
			if (!data.hasOwnProperty(key)) break;
			str += `&${key}=${data[key]}`;
		}
		return str.substring(1);
	};
	// 5.设置响应拦截器:[成功状态]把从服务器获取的结果中的响应主体信息获取到即可,[失败状态]手动把错误信息抛出异常
	axios.interceptors.response.use(function (response) {
		return response.data;
	}, function (error) {
		throw new Error(error);
	});
	// 6.配置什么才算成功(把PROMISE状态改为FULFILLED)
	axios.defaults.validateStatus = function (status) {
		return /^(2|3)\d{2}$/.test(status);
	}

	// axios.get('/json/data2.json').then(data => {
	// 	console.log(data);
	// }).catch(reason => {
	// 	console.log(reason);
	// });

	//=>Promise.all
	let promise1 = Promise.resolve(100);
	let promise2 = Promise.resolve(200);
	axios.all([promise1, promise2]).then(results => {
		let [val1, val2] = results;
		console.log(val1, val2);
	});
	/* axios.all([promise1, promise2]).then(axios.spread(function (val1, val2) {
		//=>axios.spread:把基于axios.all获取的结果一项项的单独获取到
		console.log(val1, val2);
	})) */
</script>

八、JS中的同步异步编程

JS是单线程的:大部分代码都是同步的,但是也有少部分代码是异步编程的

  • 异步的宏任务:
    • 定时器
    • ajax:一般都是异步的
    • 事件绑定
  • 异步的微任务:
    • promise中的then
    • async await
    • generator 中的yield
    • requestAnimationFrame

例题1:

setTimeout(() => {
    console.log(1);
}, 1000);
console.log(2);

在这里插入图片描述
例题2:

setTimeout(() => {
    console.log(1);
}, 20);
console.log(2);
setTimeout(() => {
    console.log(3);
}, 10);
console.log(4);
// console.time('AA');
for (let i = 0; i < 90000000; i++) {
    // do soming
}
//=>AA: 79ms 左右
// console.timeEnd('AA'); 
console.log(5);
setTimeout(() => {
    console.log(6);
}, 8);
console.log(7);
setTimeout(() => {
    console.log(8);
}, 15);
console.log(9);

//结果:2 4 5 7 9 3 1 6 8 

在这里插入图片描述
例题3:

let p = new Promise((resolve, reject) => {
    console.log(1);
    setTimeout(() => {
        resolve('OK');
        // + 改变实例的状态和值「同步」
        // + 通知之前基于then存放的onfulfilledCallback执行「异步的微任务:也是把执行方法的事情放置在EventQueue中的微任务队列中」
        console.log(p);
        console.log(4);
    }, 1000); //=>存储了一个异步的宏任务
    console.log(2);
});
console.log(p);
// 此时接受onfulfilledCallback的时候,状态还是pending,此时只把方法存储起来
p.then(result => {
    console.log('成功-->', result);
});
console.log(3);

// 结果:
// 1  
// 2 
// Promise {<pending>} 
// 3  
// Promise {<fulfilled>: "OK"}
// 4
// 成功--> OK

例题4【难】:谁先知道可执行,谁就先执行

new Promise(resolve => {
    console.log('promise1');
    resolve();
}).then(() => {
    console.log('then11');
    new Promise(resolve => {
        console.log('promise2');
        resolve();
    }).then(() => {
        console.log('then21');
    }).then(() => {
        console.log('then22');
    });
}).then(() => {
    console.log('then12');
});
//结果:promise1
//then11
//promise2
//then21
//then12
//then22

在这里插入图片描述
例题5:

new Promise(resolve => {
    console.log('promise1');
    resolve();
}).then(() => {
    console.log('then11'); 
    return new Promise(resolve => {
        console.log('promise2');
        resolve();
    }).then(() => {
        console.log('then21');
    }).then(() => {
        console.log('then22');
    });
}).then(() => {
    console.log('then12');
});
//结果:promise1
//then11
//promise2
//then21
//then22
//then12

九、async / await

1、async关键字

说明:async/await 可以被看作是 Promise 的语法糖,它们是用来更方便地处理异步操作的一种方式,用于替代传统的 .then() 链式调用,使异步代码更加线性和清晰。

“async”是异步的意思,声明的必须是一个函数,表示“异步函数”,它的返回值是一个Promise对象

async function fn() {
    return 1;
}
console.log(fn()); 
// [[Prototype]]: Promise
// [[PromiseState]]: "fulfilled"
// [[PromiseResult]]: 1

fn().then((res)=>{
    console.log(res); //1
})
2、await关键字

“await”关键字必须在使用“async”声明的异步函数的内部使用

async function fn() {
    function test() {
        await 111; //Uncaught SyntaxError: await is only valid in async functions...
    };
}
(1)await的执行机制
  • first
async function fn() {
    await setTimeout(() => {
        console.log("定时器执行")
    }, 1000);
    console.log('我执行了');
}
fn();

执行结果:
在这里插入图片描述

  • second
async function fn() {
    await new Promise((resolve,reject) => {
        setTimeout(() => {
            console.log("定时器执行");
            reject();//【注意】:如果此处执行的是失败的promise,或者
            // 既不执行成功也不执行失败的promise,下面'我执行了'的代码将不会被打印。
        }, 1000);
    })
    console.log('我执行了');
}
fn();

执行结果:
在这里插入图片描述

  • third
async function fn() {
    await new Promise((resolve,reject) => {
        setTimeout(() => {
            console.log("定时器执行");
            resolve();//【注意】:此处只有执行成功的promise,下面'我执行了'的代码才会被打印。
        }, 1000);
    })
    console.log('我执行了');
}
fn();

执行结果:
在这里插入图片描述

  • fourth
async function fn() {
    await new Promise((resolve,reject) => {
        resolve();
        setTimeout(() => {
            console.log("定时器执行");
        }, 1000);
    })
    console.log('我执行了');
}
fn();

执行结果:
在这里插入图片描述

总结如果await后面不是一个Promise对象,那么代码就按照正常的JavaScript顺序执行,先执行同步代码,再去执行异步任务【实际上async await 是promise的语法糖,一般不会有人这么些吧】。await 后如果能立即确定promise为成功态,代码就会立即按正常js执行,先执行同步再执行异步;如果不能立即确定promise的状态,则需要等待promise变为成功态,await函数体后面的代码才能执行。

(2)await的返回值
async function fn() {
    let res = await new Promise((resolve,reject) => {
        setTimeout(() => {
            console.log("定时器执行");
            resolve('返回值');
        }, 1000);
    })
    console.log('我执行了');
    console.log(res);
}
fn();

执行结果:
在这里插入图片描述

总结:await后面如果是Promise对象,那么await的返回值就是Promise对象的resolve/reject返回结果。

3、async / await异常处理
(1)外部处理
async function fn() {
    await new Promise((resolve, reject) => reject('错误的值'));
};
fn().catch((data) => console.log(data)); //错误的值

总结:async函数返回的是一个Promise对象,我们可以在外面使用catch接收错误值。

(2)内部处理
async function fn() {
    try {
        await new Promise((resolve, reject) => {resolve('成功的返回值');})
        await new Promise((resolve, reject) => {reject('错误的返回值');})
    } catch (error) {
        console.log(error);
    }
}
fn();

总结:当await 的返回值为reject状态 ,可以通过try catch在函数内部进行异常捕获。

4、async / await优势

需求:1秒后执行第一个请求,执行完第一个请求后,3秒后执行第二个请求,执行完第二个请求后,5秒后执行第三个请求!

  • promise.then实现
let request1 = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('request1返回的值');
        }, 1000);
    });
};

let request2 = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('request2返回的值');
        }, 3000);
    });
};

let request3 = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('request3返回的值');
        }, 5000);
    });
};

request1().then((data1) => {
    console.log(data1);
    return request2();
}).then((data2) => {
    console.log(data2);
    return request3();
}).then((data3) => {
    console.log(data3);
})
  • async / await实现
let request1 = () => {
   return new Promise((resolve, reject) => {
       setTimeout(() => {
           resolve('request1返回的值');
       }, 1000);
   });
};

let request2 = () => {
   return new Promise((resolve, reject) => {
       setTimeout(() => {
           resolve('request2返回的值');
       }, 3000);
   });
};

let request3 = () => {
   return new Promise((resolve, reject) => {
       setTimeout(() => {
           resolve('request3返回的值');
       }, 5000);
   });
};

async function request(){
   const data1 = await request1();
   console.log(data1);
   const data2 = await request2();
   console.log(data2);
   const data3 = await request3();
   console.log(data3);
}
request();

执行结果都是一样的:
在这里插入图片描述

总结:使用async / await实现需求,语义化更加清楚,代码可读性更高!

十、手撕promise源码【基础版】

/* 
 * 基于原生JS实现Promise「遵循的是Promise A Plus规范」
 *    https://promisesaplus.com/ 
 */
(function () {
    "use strict";

    /* 核心 */
    function Promise(executor) {
        var self = this,
            change;

        // 参数格式处理:
        //   + 只允许new执行,不允许把其当做普通函数执行
        //   + 传递的executor必须是一个函数
        if (typeof self === "undefined") throw new TypeError('undefined is not a promise');
        if (typeof executor !== "function") throw new TypeError('Promise resolver ' + executor + ' is not a function');

        // 初始化私有属性
        self.state = 'pending';
        self.result = undefined;
        self.onFulfilledCallbacks = [];
        self.onRejectedCallbacks = [];

        change = function change(state, result) {
            if (self.state !== "pending") return;
            self.state = state;
            self.result = result;
            // 通知基于then存储的方法执行「两个集合中的方法执行」
            if (self.onFulfilledCallbacks.length === 0 && self.onRejectedCallbacks.length === 0) return;
            setTimeout(function () {
                var i = 0,
                    callbacks = self.state === "fulfilled" ? self.onFulfilledCallbacks : self.onRejectedCallbacks,
                    len = callbacks.length,
                    item;
                for (; i < len; i++) {
                    item = callbacks[i];
                    typeof item === "function" ? item(self.result) : null;
                }
            });
        };

        // 立即执行executor
        try {
            executor(function resolve(result) {
                change('fulfilled', result);
            }, function reject(reason) {
                change('rejected', reason);
            });
        } catch (err) {
            change('rejected', err);
        }
    }
    Promise.prototype = {
        constructor: Promise,
        customer: true,
        then: function (onfulfilled, onrejected) {
            if (typeof onfulfilled !== "function") {
                onfulfilled = function onfulfilled(result) {
                    return result;
                };
            }
            if (typeof onrejected !== "function") {
                onrejected = function onrejected(reason) {
                    throw reason;
                };
            }

            var self = this;
            switch (self.state) {
                case 'fulfilled':
                    // queueMicrotask(callback):创建异步的微任务「兼容性不好」
                    setTimeout(function () {
                        onfulfilled(self.result);
                    });
                    break;
                case 'rejected':
                    setTimeout(function () {
                        onrejected(self.result);
                    });
                    break;
                default:
                    // 把传递进来的函数事先存储起来,以后执行resolve/reject的时候通知这些方法执行
                    self.onFulfilledCallbacks.push(onfulfilled);
                    self.onRejectedCallbacks.push(onrejected);
            }
        },
        catch: function (onrejected) {
            var self = this;
            return self.then(null, onrejected);
        }
    };
    if (typeof Symbol !== "undefined") {
        Promise.prototype[Symbol.toStringTag] = 'Promise';
    }
    Promise.resolve = function resolve(value) {
        return new Promise(function (resolve) {
            resolve(value);
        });
    };
    Promise.reject = function reject(value) {
        return new Promise(function (_, reject) {
            reject(value);
        });
    };
    Promise.all = function all(promises) {};

    /* 暴露API */
    if (typeof window !== "undefined") {
        // window.Promise = Promise;
    }
    if (typeof module === "object" && typeof module.exports === "object") {
        // module.exports = Promise;
    }


    var p1 = new Promise(function (resolve, reject) {
        /* setTimeout(() => {
            reject('NO');
        }, 1000); */
        reject('NO');
    });
    p1.then(function (result) {
        console.log('成功', result);
    });
    p1.then(null, function (reason) {
        console.log('失败', reason);
    });
    console.log(1);
})();

十一、手撕promise源码【then链+all】

(function () {
    "use strict";
    /* 工具 */
    var isArray = function isArray(value) {
        var type = Object.prototype.toString.call(value);
        return /^\[object Array\]$/i.test(type);
    };
    var isPromise = function isPromise(x) {
        if (x == null) return false;
        if (/^(object|function)$/i.test(typeof x)) {
            if (typeof x.then === "function") {
                return true;
            }
        }
        return false;
    };
    var handle = function handle(promise, x, resolve, reject) {
        if (x === promise) throw new TypeError('Chaining cycle detected for promise #<Promise>');
        if (isPromise(x)) {
            try {
                x.then(resolve, reject);
            } catch (err) {
                reject(err);
            }
            return;
        }
        resolve(x);
    };

    /* 核心 */
    function Promise(executor) {
        var self = this,
            change;
        if (typeof self === "undefined") throw new TypeError('undefined is not a promise');
        if (typeof executor !== "function") throw new TypeError('Promise resolver ' + executor + ' is not a function');

        self.state = 'pending';
        self.result = undefined;
        self.onFulfilledCallbacks = [];
        self.onRejectedCallbacks = [];
        change = function change(state, result) {
            if (self.state !== "pending") return;
            self.state = state;
            self.result = result;
            if (self.onFulfilledCallbacks.length === 0 && self.onRejectedCallbacks.length === 0) return;
            setTimeout(function () {
                var i = 0,
                    callbacks = self.state === "fulfilled" ? self.onFulfilledCallbacks : self.onRejectedCallbacks,
                    len = callbacks.length,
                    item;
                for (; i < len; i++) {
                    item = callbacks[i];
                    typeof item === "function" ? item(self.result) : null;
                }
            });
        };

        try {
            executor(function resolve(result) {
                change('fulfilled', result);
            }, function reject(reason) {
                change('rejected', reason);
            });
        } catch (err) {
            change('rejected', err);
        }
    }
    Promise.prototype = {
        constructor: Promise,
        customer: true,
        then: function (onfulfilled, onrejected) {
            if (typeof onfulfilled !== "function") {
                onfulfilled = function onfulfilled(result) {
                    return result;
                };
            }
            if (typeof onrejected !== "function") {
                onrejected = function onrejected(reason) {
                    throw reason;
                };
            }

            var self = this,
                promiseNew,
                x;
            promiseNew = new Promise(function (resolve, reject) {
                switch (self.state) {
                    case 'fulfilled':
                        setTimeout(function () {
                            try {
                                x = onfulfilled(self.result);
                                handle(promiseNew, x, resolve, reject);
                            } catch (err) {
                                reject(err);
                            }
                        });
                        break;
                    case 'rejected':
                        setTimeout(function () {
                            try {
                                x = onrejected(self.result);
                                handle(promiseNew, x, resolve, reject);
                            } catch (err) {
                                reject(err);
                            }
                        });
                        break;
                    default:
                        self.onFulfilledCallbacks.push(function (result) {
                            try {
                                x = onfulfilled(result);
                                handle(promiseNew, x, resolve, reject);
                            } catch (err) {
                                reject(err);
                            }
                        });
                        self.onRejectedCallbacks.push(function (reason) {
                            try {
                                x = onrejected(reason);
                                handle(promiseNew, x, resolve, reject);
                            } catch (err) {
                                reject(err);
                            }
                        });
                }
            });
            return promiseNew;
        },
        catch: function (onrejected) {
            var self = this;
            return self.then(null, onrejected);
        }
    };
    if (typeof Symbol !== "undefined") {
        Promise.prototype[Symbol.toStringTag] = 'Promise';
    }
    Promise.resolve = function resolve(value) {
        return new Promise(function (resolve) {
            resolve(value);
        });
    };
    Promise.reject = function reject(value) {
        return new Promise(function (_, reject) {
            reject(value);
        });
    };
    Promise.all = function all(promises) {
        var legal = true;
        typeof Symbol !== "undefined" ? (typeof promises[Symbol.iterator] !== "function" ? legal = false : null) : (!isArray(promises) ? legal = false : null);
        if (legal === false) throw new TypeError(promises + ' is not iterable');
        return new Promise(function (resolve, reject) {
            var i = 0,
                len = promises.length,
                index = 0,
                item,
                results = [];
            for (; i < len; i++) {
                (function (i) {
                    item = promises[i];
                    if (!isPromise(item)) item = Promise.resolve(item);
                    item.then(function (result) {
                        index++;
                        results[i] = result;
                        if (index >= len) resolve(results);
                    }, reject);
                })(i);
            }
        });
    };

    /* 暴露API */
    if (typeof window !== "undefined") {
        window.Promise = Promise;
    }
    if (typeof module === "object" && typeof module.exports === "object") {
        module.exports = Promise;
    }
})();

//===========测试
/* var p1 = new Promise(function (resolve, reject) {
    resolve('OK');
}).then(function (result) {
    console.log('成功', result);
    return a;
}).then(function (result) {
    console.log('成功', result);
}).catch(function (reason) {
    console.log('失败', reason);
}); */

/* const query = interval => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (interval === 1000) reject(interval);
            resolve(interval);
        }, interval);
    });
};

var p = Promise.all([query(3000), query(1000), query(2000), 4000]);
p.then(function (results) {
    console.log('成功', results);
}).catch(function (reason) {
    console.log('失败', reason);
}); */

十二、Iterator遍历器

/*
 * 遍历器(Iterator)是一种机制(接口):为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口,就可以完成遍历操作,依次处理该数据结构的所有成员
 *   + 拥有next方法用于依次遍历数据结构的成员
 *   + 每一次遍历返回的结果是一个对象 {done:false,value:xxx}
 *     + done:记录是否遍历完成
 *     + value:当前遍历的结果
 * 
 * 拥有Symbol.iterator属性的数据结构(值),被称为可被遍历的,可以基于for of循环处理
 *   + 数组
 *   + 部分类数组:arguments/NodeList/HTMLCollection...
 *   + String
 *   + Set
 *   + Map
 *   + generator object
 *   + ...
 * 
 * 对象默认不具备Symbol.iterator,属于不可被遍历的数据结构
 */
class Iterator {
    constructor(assemble) {
        let self = this;
        self.assemble = assemble;
        self.index = 0;
    }
    next() {
        let self = this;
        if (self.index > self.assemble.length - 1) {
            return {
                done: true,
                value: undefined
            };
        }
        return {
            done: false,
            value: self.assemble[self.index++]
        };
    }
}
/* let itor = new Iterator([10, 20, 30, 40]);
console.log(itor.next());
console.log(itor.next());
console.log(itor.next());
console.log(itor.next());
console.log(itor.next()); */

// for of循环就是按照迭代器的规范去遍历集合中的每一项的
//   + 每一次迭代都会去找集合中的某个属性:Symbol.iterator「具备这个属性的对象属于可以被迭代的对象,才能使用for of循环,没有则不能使用这个循环」
//   + let itor=arr[Symbol.iterator]()
//   + itor.next() -> {done:false,value:xxx}
//   + ...
//   + done决定循环是否执行 value的值给item

/* Array.prototype[Symbol.iterator] = function () {
    // this->arr当前迭代的集合
    let self = this,
        index = 0;
    return {
        next() {
            if (index > self.length - 1) {
                return {
                    done: true,
                    value: undefined
                };
            }
            return {
                done: false,
                value: self[index++]
            };
        }
    };
}; */

/* Array.prototype[Symbol.iterator] = function () {
    return new Iterator(this);
};

let arr = [10, 20, 30, 40];
for (let item of arr) {
    console.log(item);
} */


// 是否可以基于for of直接遍历对象?
//   + 不能直接遍历
//   + 需要手动设置Symbol.iterator
/* let obj = {
    0: 1,
    1: 2,
    2: 3,
    length: 3,
    // [Symbol.iterator]: Array.prototype[Symbol.iterator]
    [Symbol.iterator]: function () {
        return new Iterator(this);
    }
};
for (let item of obj) {
    console.log(item);
} */

十三、generator生成器

/*
 * 生成器对象是由一个generator function返回的,并且它符合可迭代协议和迭代器协议
 *   https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Generator
 * 
 * 普通函数 VS 生成器函数
 *    生成器函数 [[IsGenerator]]:true
 *    
 *   「把它当做一个实例 __proto__」
 *       普通函数是 Function 的实例,普通函数.__proto__===Function.prototype
 *       生成器函数是 GeneratorFunction 的实例,生成器函数.__proto__===GeneratorFunction.prototype -> 
 *                  GeneratorFunction.prototype.__proto__===Function.prototype
 *      ({}).toString.call(生成器函数) => "[object GeneratorFunction]"
 *    
 *   「把它作为一个构造函数 prototype」
 *      生成器函数不能被new执行  Uncaught TypeError: func is not a constructor
 *      当做普通函数执行,返回的结果就是生成器函数的一个实例
 *      itor.__proto__ -> func.prototype「空对象,没有constructor」 -> Generator.prototype「constructor:GeneratorFunction」{next/return/throw/Symbol(Symbol.toStringTag): "Generator"} -> 一个具备迭代器规范的对象「Symbol(Symbol.iterator)」 -> Object.prototype
 */

/* function* func() {
    console.log(1);
    return 2;
}
let itor = func();
console.log(itor.next()); //->{done:true,value:2}
console.log(itor.next()); //->{done:true,value:undefined} */

// 每一次执行next,遇到yield会暂停函数的执行
//   + done
//   + value -> yield后面的值
/* function* func() {
    console.log('A');
    yield 1;

    console.log('B');
    yield 2;

    console.log('C');
    yield 3;

    console.log('D');
    return 4;
}
let itor = func(); */

/* console.log(itor.next()); //->{done:false,value:1}
console.log(itor.next()); //->{done:false,value:2}
console.log(itor.next()); //->{done:false,value:3}
console.log(itor.next()); //->{done:true,value:4}
console.log(itor.next()); //->{done:true,value:undefined} */

/* console.log(itor.next()); //->{done:false,value:1}
console.log(itor.next()); //->{done:false,value:2}
console.log(itor.return(10)); //->{done:true,value:10}  把生成器内部的执行直接停止,让done变为true「throw直接抛异常,下面代码都不执行了」
console.log(itor.next()); //->{done:true,value:undefined}
console.log(itor.next()); //->{done:true,value:undefined} */

/* console.log(itor.next()); //->{done:false,value:1}
console.log(itor.next()); //->{done:false,value:2}
console.log(itor.throw(10)); //->「throw直接抛异常,下面代码都不执行了」
console.log(itor.next()); 
console.log(itor.next()); */


// 执行next还可以传递值「第一次没必要,其余每次传递的值,都是给上一次yield的处理结果」
// 生成器函数中的this不是其实例,而是window/undefined
/* function* func() {
    let x1 = yield 1;
    console.log(x1);

    let x2 = yield 2;
    console.log(x2);
}
let itor = func();
console.log(itor.next()); //->{done:false,value:1}
console.log(itor.next(10)); //->{done:false,value:2}
console.log(itor.next(20)); //->{done:true,value:undefined} */

/* function* func1() {
    yield 1;
    yield 2;
}

function* func2() {
    yield 3;
    yield* func1();
    yield 4;
}
let itor = func2();
console.log(itor.next()); //->{done:false,value:3}
console.log(itor.next()); //->{done:false,value:1}
console.log(itor.next()); //->{done:false,value:2}
console.log(itor.next()); //->{done:false,value:4} */




//==============
const query = interval => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(interval);
        }, interval);
    });
};

/* query(1000).then(res1 => {
    return query(2000);
}).then(res2 => {
    return query(3000);
}).then(res3 => {
    console.log(res3);
}); */

/* (async () => {
    let res1 = await query(1000);
    console.log(res1);

    let res2 = await query(2000);
    console.log(res2);

    let res3 = await query(3000);
    console.log(res3);
})(); */


var isPromise = function isPromise(x) {
    if (x == null) return false;
    if (/^(object|function)$/i.test(typeof x)) {
        if (typeof x.then === "function") {
            return true;
        }
    }
    return false;
};
// async await处理的事情:构建generator执行器
function AsyncFunction(generator) {
    return new Promise(resolve => {
        let itor = generator();
        const next = x => {
            let {
                value,
                done
            } = itor.next(x);
            if (done) {
                resolve(value);
                return;
            }
            if (!isPromise(value)) value = Promise.resolve(value);
            value.then(next).catch(reason => {
                // 如果返回的实例是失败态,则抛出异常信息
                itor.throw(reason);
            });
        };
        next();
    });
}
AsyncFunction(function* () {
    try {
        let res1 = yield query(1000);
        console.log(res1);

        let res2 = yield Promise.reject('NO');
        console.log(res2);

        let res3 = yield query(3000);
        console.log(res3);
    } catch (err) {
        console.log(err);
    }
    return 'ok';
}).then(result => {
    console.log('generator都执行完', result);
});

/* function* gen() {
    let res1 = yield query(1000);
    console.log(res1);

    let res2 = yield query(2000);
    console.log(res2);

    let res3 = yield query(3000);
    console.log(res3);
}
let itor = gen();
// console.log(itor.next()); //->{done:false,value:promise实例}
itor.next().value.then(res1 => {
    // res1->第一个请求的结果
    itor.next(res1).value.then(res2 => {
        // res2->第二个请求的结果
        itor.next(res2).value.then(res3 => {
            // res3->第二个请求的结果
            itor.next(res3); //->此时{done:true,value:undefined}
        });
    });
}); */
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐