Part8: promise、axios、JS中的同步异步、async / await、iterator、generator
一、promise和Ajax的串行并行
一、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}
});
});
}); */
更多推荐
所有评论(0)