Promise
ES6 语法规范中新增加的内置类,用来处理 JS 中异步编程的,而我们所谓的 promise 设计模式,就是基于 promise 对异步操作进行管理。
对Ajax中的串行、并行导致的回调地狱、其他乱七八糟的事,进行管控。
我的理解:执行Promise的执行器函数executor过程中,如果执行了resolve函数,表示异步操作成功,把PromiseStatus改为fulfilled / resolved,Promise实例的then中执行resolved对应的方法;如果执行了reject函数,表示异步操作失败,把PromiseStatus改为rejected,Promise实例的then中执行rejected对应的方法。
在执行异步操作,等待的过程中,调用 实例.then(),往事件池【不是事件池】中添加 异步成功、失败对应的方法。【 .then()时,还不会执行.then()中的方法,只是把方法加进去。】
异步操作结束后,根据PromiseStatus,执行.then()中对应的方法。
实例.then():有2个方法,到底执行哪个方法,由当前实例的状态、value决定【value无关】。如果是executor函数,那就看执行resolve 还是 reject;如果不是executor函数,是then()中的函数,就看函数执行有没有报错,不管执行的是then()中的第几个函数。
异步编程中的“回调地狱”,Ajax 的串行、并行
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() {
// func虽然被调用3次,但是count >= 3,才会执行if中的代码
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();
}
});
let p1 = new Promise((resolve, reject) => {
console.log(111)
})
console.log(p1)
let p1 = new Promise((resolve, reject) => {
console.log(111)
resolve()
})
console.log(p1)
Promise基础语法
executor和状态
let PromiseExamp = new Promise(); // => Uncaught TypeError: Promise resolver undefined is not a function
// --------------------------------------
/*
* new Promise([executor]): 第一个执行函数必须传递
* [executor 简称exe]
* 1.exe是Promise类的一个回调函数,exe函数中放的就是当前要处理的异步操作,Promise内部会把它执行。
* new Promise的时候就会把exe执行,创建Promise的一个实例。
* 2.Promise不仅把exe执行,而且还给exe传递两个参数(两个参数也是函数类型):
* => resolve函数:它执行代表Promise处理的异步操作是成功的,把Promise的状态改为fulfilled。
* => reject函数:它执行代表Promise处理的异步操作是失败的,把Promise的状态改为rejected。
*/
let PromiseExamp = new Promise((resolve, reject) => {
// => 这里一般存放的都是即将要处理的异步任务,任务成功,执行resolve;任务失败,执行reject。当然,写同步的也可以。
// 【executor不报错,还需要在executor中手动调用resolve,才会执行Promise实例的then函数中的完成处理函数;executor报错,不需要在executor中手动调用reject,就会执行Promise实例的then函数中的拒绝处理函数。】
let ran = Math.random();
setTimeout(() => {
if (ran < 0.5) {
reject(ran);
return;
}
resolve(ran);
}, 1000);
});
PromiseExamp.then(result => {
// => 状态为fulfilled成功后执行(result:[[PromiseValue]])
console.log(‘成功: ‘ + result);
}, error => {
// => 状态为rejected失败后执行
console.log(‘失败: ‘ + error);
});
js中的异常处理
// js中的异常处理
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); // a is not defined
}
try {
throw new Error(‘嘻嘻嘻‘)
} catch (e) {
console.log(e.message); // 嘻嘻嘻
}
try {
throw ‘哈哈哈‘
} catch (e) {
console.log(e); // 哈哈哈
}
let b = 10;
console.log(b);
then、catch、finally
/*
* Promise.prototype
* then: 设置成功或者失败后执行的方法(成功或者失败都可以设置,也可以只设置一个)
* pro.then([success], [error])
* pro.then([success])
* pro.then(null, [error])
* catch: 设置失败后执行的方法
* finally: 设置不论成功还是失败都会执行的方法(一般不用)
*/
let PromiseExamp = new Promise((resolve, reject) => {
setTimeout(() => {
let ran = Math.random();
ran < 0.5 ? reject(ran) : resolve(ran);
}, 100);
});
PromiseExamp.then(result => {
console.log(‘成功: ‘ + result);
});
PromiseExamp.catch(error => {
console.log(‘失败: ‘ + error);
});
PromiseExamp.finally(x => {
console.log(‘哈哈‘);
});
// 使用链式写法,则不会像上面那样:ran < 0.5 时,控制台报错
let PromiseExamp = new Promise((resolve, reject) => {
setTimeout(() => {
let ran = Math.random();
ran < 0.5 ? reject(ran) : resolve(ran);
}, 100);
});
PromiseExamp.then(result => {
console.log(‘成功: ‘ + result);
}).catch(error => {
console.log(‘失败: ‘ + error);
}).finally(x => {
console.log(‘哈哈‘);
});
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
let ran = Math.random();
ran < 0.5 ? reject(ran) : resolve(ran);
}, 100);
})
p1.then(result => console.log(‘成功: ‘ + result));
p1.catch(error => console.log(‘失败: ‘ + error));
p1.finally(() => console.log(‘嘻嘻嘻‘));
console.log(‘-----------------------------‘)
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
let ran = Math.random();
ran < 0.5 ? reject(ran) : resolve(ran);
}, 100);
});
p2.then(result => console.log(‘成功: ‘ + result))
.catch(error => console.log(‘失败: ‘ + error))
.finally(() => console.log(‘哈哈哈‘))
then链
let pro1 = new Promise((resolve, reject) => {
setTimeout(() => {
let ran = Math.random();
console.log(ran)
ran < 0.5 ? reject(ran) : resolve(ran);
}, 100);
});
// 刚开始,pro1【.then】的状态是pedding。当pro1.then中2个方法中的任意一个执行,报错、成功、失败,只要执行的结果没报错,说明是成功的;可能这里又会返回一个异步操作的结果。2个方法中的任意一个执行,只要成功了,都会把pro3的 完成处理函数 执行;反之,则执行拒绝处理函数。第二次then监听的是 这个then的2个回调函数的执行结果
let pro2 = pro1.then(result => {
console.log(`PRO1: SUCCESS`);
}, error => {
console.log(`PRO1: ERROR`)
});
// 当pro2的状态为fulfilled 或 rejected时,执行pro2.then中的某个方法
let pro3 = pro2.then(result => {
console.log(`PRO2: SUCCESS`);
}, error => {
console.log(`PRO2: ERROR`)
});
// ---------------------------------------
// => then(onResolve,onReject)
// 执行then、catch、finally返回的结果是一个全新的Promise实例,所以可以链式写下去;下一个then中哪个方法会被执行,由上一个then中某个方法执行的结果来决定
// 上一个then中某个方法的返回值会传递给下一个then的某个方法中
// 实例.then():有2个方法,到底执行哪个方法,由当前实例的状态、value决定【alue无关】。如果是executor函数,那就看执行resolve 还是 reject;如果不是executor函数,是then()中的函数,就看函数执行有没有报错,不管执行的是then()中的第几个函数
new Promise((resolve, reject) => {
// resolve(100); // => 把第一个Promise实例的value值改为100/-100
reject(-100);
}).then(result => {
console.log(result);
// then中RETURN的结果相当于把当前这个新的Promise实例中的value值改为返回值
return result * 10;
}, 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;
});
// --------------------------------
// 第一个.then()返回一个新的Promise实例
new Promise((resolve, reject) => {
resolve(100);
}).then(A => {
// => 执行报错,让.then创建的Promise实例变为失败状态,并且把报错的原因作为此Promise的value值
// 【而不是把return 的 A * 10作为返回值,其实这行代码报错,这个then中下面的代码就不会执行了。】
console.log(AAAAA);
return A * 10;
}).catch(B => {
console.log(B); // => ReferenceError: AAAAA is not defined
return ‘@‘;
}).then(C => {
console.log(C); // => ‘@‘
});
// --------------------------------
// (1)第一个Promise成功,找第1个then中的第一个函数,没有,不会报错,顺延到下一个成功;(2)第一个catch不代表成功,跳过;(3)找到第2个then中的第一个函数,执行,没报错,成功;(4)第3个then中的第一个函数,执行,没报错,成功;(5)第2个catch不执行;(6)第3个then是成功,第2个catch不执行,所以执行第4个then,报错;(7)执行第3个catch,没东西,顺延;(8)执行最后一个then的拒绝处理函数。
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
});
promise的应用:解决Ajax的串行、并行
< !--解决AJAX回调地狱 -->
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();
< !--解决AJAX并行 -->
function ajax1() {
return new Promise(resolve => {
$.ajax({
url: ‘/api1‘,
// 相当于 success: res => resolve(res)
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状态最先处理完(成功或者失败),以最先处理完的为主
});
报错问题
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
let ran = Math.random();
ran < 0.5 ? reject(ran) : resolve(ran);
}, 1000);
})
p1.then(result => console.log(‘成功: ‘ + result))
p1.catch(error => console.log(‘失败: ‘ + error))
p1.finally(() => console.log(‘嘻嘻嘻‘))
console.log(‘-----------------------------‘)
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
let ran = Math.random();
ran < 0.5 ? reject(ran) : resolve(ran);
}, 1000);
});
p2.then(result => console.log(‘成功: ‘ + result))
.catch(error => console.log(‘失败: ‘ + error))
.finally(() => console.log(‘哈哈哈‘))
547 Promise:Ajax 的串行、并行,executor和状态,then、catch、finally,then链,,,,,,,,