一、异步编程:
- fs 文件操作
require('fs').readFile('./index.html',(err,data)=>{})
- AJAX
$.get('./server',(data)=>{})
- 数据库操作
- 定时器
setTimeout(()=>{},1000)
二、地狱回调问题
概念:回调函数嵌套,外部回调函数异步执行的结果是嵌套的回调函数的执行条件。
三、Promise介绍与使用
promise是异步编程的新的解决方案(ES6规范),它是一个构造函数。
可以实例化对象,封装异步操作,获取成功和失败的结果。
优点:支持链式调用,可以解决地狱回调问题,执行的方式更为灵活。
promise初体验——抽奖
<body>
<div class="container">
<h2 class="page-header">promise初体验</h2>
<button class="btn btn-primary" id="btn">点击抽奖</button>
</div>
<script>
function rand(m, n) {
return Math.ceil(Math.random() * (n - m + 1)) + m - 1;
}
const btn = document.querySelector("#btn");
btn.addEventListener('click', function () {
// setTimeout(()=>{
// let n=rand(1,100);
// if(n<=30){
// alert("中奖了");
// }else{
// alert("再接再厉");
// }
// },1000);
// promise形式
const p = new Promise((resolve, reject) => {
setTimeout(() => {
let n = rand(1, 100);
if (n <= 30) {
resolve(n);
} else {
reject(n);
}
}, 1000);
})
p.then((data) => {
alert(`中奖了,数字为${data}`);
}, (data) => {
alert(`再接再厉,数字为${data}`);
})
});
</script>
</body>
promise实践练习——AJAX请求
<script>
const btn = document.querySelector("#btn");
btn.addEventListener('click', function () {
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.apiopen.top/getJoke');
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve('成功');
} else {
reject('失败');
}
}
}
})
p.then((data) => {
console.log(data);
}, (err) => {
console.log(err);
})
})
</script>
promise实践练习——fs文件读取
<script>
const fs = request('fs');
//回调函数形式
// fs.readFile('./resource/content.txt',(err,data)=>{
// if(err){
// throw err;
// }else{
// console.log(data.toString());
// }
// })
//promise形式
let p = new Promise((resolve, reject) => {
fs.readFile('./resource/content.txt', (err, data) => {
if (err) {
reject(data);
}
resolve(err);
});
})
p.then((data) => {
console.log(data.toString());
}, (err) => {
console.log(err);
});
</script>
四、promise对象的状态——PromiseState
实例对象中的一个属性 『PromiseState』,状态只能改变一次。
* pending 未决定的
* resolved / fullfilled 成功
* rejected 失败
五、promise对象的结果——PromiseResult
实例对象中的另一个属性 『PromiseResult』
保存着异步任务『成功/失败』的结果
六、promise的API
(1)promise构造函数可以通过 new 实例化对象
- Promise(executor){}
- 参数:executor执行器——(resolve,reject)=>{}
(2)Promise.prototype.then((onResolved,onRejected)=>{});
- 参数返回结果是:throw ‘error’;则最终的promise就是一个失败的promise对象。
- 参数返回结果是非promise对象:return 521;则最终的promise就是一个成功的promise对象,promiseState结果为521。
- onResolved() 返回结果是promise对象:return Promise.resolve(521);则最终的promise就是一个成功的promise对象,promiseState结果为521。
- onRejected() 返回结果是promise对象:return Promise.reject(521);则最终的promise就是一个失败的promise对象,promiseState结果为521。
var p = new Promise((resolve, reject)=>{
resolve('ok');
});
let result = p.then((value) => {
//1.抛出错误
// throw '出问题了';
//2.返回一个非Promise类型的对象
// return 521;
//3.返回一个Promise类型的对象
return Promise.resolve(521);
// return new Promise((resolve, reject)=>{
// //resolve('ok');
// reject('error');
// })
})
console.log(result);
(3)Promise.prototype.catch((onRejected)=>{});
(4)Promise.resolve((value)=>{});
- Promise函数对象上的方法,不是实例对象上的方法。
- 如果参数为非promise对象,返回结果为成功的promise对象。
- 如果参数为promise对象,参数的结果决定了resolve()返回的结果。
(5)Promise.reject((err)=>{});
- Promise函数对象上的方法,不是实例对象上的方法。
- 始终返回一个失败的promise对象;
- 传入什么,PromiseResult就是什么;
(6)Promise.all((promises)=>{})
- promises:是一个数组,包含n个promise
- 返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败就直接失败。
(7)Promise.race((promises)=>{})
- promises:是一个数组,包含n个promise
- 返回一个新的promise,第一个改变promise的结果状态就是最终的结果状态。
七、promise的关键问题
1.如何改变promise对象的状态?
resolve()
reject()
throw 'error';
2.当一个promise制定了多个成功或失败的回调,都会执行吗?
答:对应状态的回调函数都会执行。
3.改变promise状态和指定回调函数哪个先哪个后?
答:都有可能。一般都是先指定回调再改变状态。
- 如何先指定回调再改变状态?
答:改变状态调用resolve()为异步任务时(添加延时器) - 如何先改变状态再指定回调?
(1)直接同步调用resolve()/reject();(同步任务)
(2)延迟调用then()方法。 - 什么时候能得到数据?
答:回调函数调用后就会得到数据。
4.promise如何串联多个任务?(重点)
var p = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('ok');
},2000);
});
p.then((value)=>{
return new Promise((resolve,reject)=>{
resolve('success');
})
})//返回一个成功的promise对象,状态为成功,结果值为success
.then(value=>{
console.log(value);//success
})//value为上一层返回的结果值,即一个成功的promise对象,成功的结果值为:success,则输出的结果就为:success,且本身的then()方法无返回值。
.then(value=>{
console.log(value);//undefined
})//value为上一层返回的结果值(上一次无返回值),则输出的结果为undefined。且本身的then()方法无返回值。
5.异常穿透
只需要在最后指定一个失败的回调即可。
var p = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('ok');//执行了所有的回调函数then(),输出结果:111 222 333
//reject('Err');//直接穿透执行回调函数catch(),输出结果:'Err'。
},2000);
});
p.then((value)=>{
//console.log(111);
throw '出错了';//直接穿透执行回调函数catch(),输出结果:'出错了'。
}).then((value)=>{
console.log(222);
}).then((value)=>{
console.log(333);
}).catch((err)=>{
console.warn(err);
});
6.终止promise的链式操作
答:返回一个pending状态的promise对象
p.then(()=>{
return new Promise(()=>{})//状态未改变不会执行后续的方法
}).then((value)=>{
console.log(222);
}).then((value)=>{
console.log(333);
})
八、手写Promise
声明的构造函数
function Promise(executor) {
// console.log(this);//Promise
var _this = this;//that self _this
//初始化这个Promise构造函数的属性
this.PromiseState = "pending";
this.PromiseResult = null;
this.callbacks = [];
// resolve函数
function resolve(val) {
// console.log(this);//Window
if (_this.PromiseState === "pending") {
_this.PromiseState = "fulfilled";
_this.PromiseResult = val;
// if(_this.callback.onResolved){
// _this.callback.onResolved(val);
// }
setTimeout(()=>{
_this.callbacks.forEach((item) => {
item.onResolved(val);
})
})//异步执行
}
}
// reject函数
function reject(err) {
// console.log(this);//Window
if (_this.PromiseState === "pending") {
_this.PromiseState = "rejected";
_this.PromiseResult = err;
// if(_this.callback.onRejected){
// _this.callback.onRejected(err);
// }
setTimeout(()=>{
_this.callbacks.forEach((item) => {
item.onRejected(err);
})
})//异步执行
}
}
try {
//同步调用执行器函数
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then方法
Promise.prototype.then = function (onResolved, onRejected) {
var _this = this;
//判断回调函数参数是否传递第二个回调onRejected
if(typeof onResolved !=='function'){
onResolved=v=>{
return v;
}
}
if(typeof onRejected !=='function'){
onRejected=r=>{
throw r;
}
}
return new Promise((resolve, reject) => {
function callback(type) {
try {
let result = type(_this.PromiseResult);
//返回promise对象
if (result instanceof Promise) {
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
//状态为成功(返回非promise对象)
resolve(result);
}
} catch (e) {
//throw
reject(e);
}
}
//同步修改then方法的返回结果
if (this.PromiseState === "fulfilled") {
setTimeout(()=>{
callback(onResolved);
})//异步执行
}
if (this.PromiseState === "rejected") {
setTimeout(()=>{
callback(onRejected);
})//异步执行
}
//解决异步任务状态为pending,如何执行后续代码的问题
if (this.PromiseState === "pending") {
//保存回调函数
this.callbacks.push({
onResolved: function () {
// console.log('success');
callback(onResolved);
},
onRejected: function () {
// console.log('error');
callback(onRejected);
}
})
}
})
}
catch方法
Promise.prototype.catch=function(onRejected){
return this.then(undefined,onRejected);
}
resolve方法
Promise.resolve=function(value){
return new Promise((resolve, reject) => {
if(value instanceof Promise){
value.then((v)=>{
resolve(v);
},(r)=>{
reject(v);
})
}else{
resolve(value);
}
})
}
reject方法:永远返回一个失败的promise对象
Promise.reject=function(value){
return new Promise((resolve, reject) => {
reject(value);
})
}
all方法
Promise.all=function(promises){
//返回结果为promise对象
return new Promise((resolve, reject) => {
let count=0;
let arr=[];
for(let i=0;i<promises.length;i++){
promises[i].then(v=>{
//状态为成功
//每个promise对象都成功才成功
count++;
//结果放到arr中
// arr.push(v);//顺序可能打乱
arr[i]=v;
if(count === promises.length){
resolve(arr);
}
},r=>{
//状态为失败
reject(r);
})
}
})
}
race方法
Promise.race=function(promises){
return new Promise((resolve, reject) => {
for(let i=0;i<promises.length;i++){
promises[i].then((v)=>{
resolve(v);
},(r)=>{
reject(r);
})
}
})
}
九、async和await
async函数:
- 函数的返回结果为promise对象
- promise对象的结果由async函数执行的返回值决定
async function main() {
//1.返回一个非promise对象
// return 521;//main函数的返回结果为成功的promise对象
//2.返回一个promise对象
// return new Promise((resolve, reject) => {
// resolve();
// })
// return new Promise((resolve, reject) => {
// reject();
// })
//3.抛出错误
throw '出错啦';
}
let result = main();
console.log(result);
await函数:
- await右侧的表达式一般为promise对象,但也可以是其他值
- 右侧的表达式为promise对象,await 返回结果是promise对象成功的值
- 右侧的表达式为其他类型值,await 返回结果直接就是该值
- await必须出现在async中,但是async函数中可以没有await
- 如果await的promise失败了,就会抛出异常,使用try…catch捕获处理
async function main() {
let p = new Promise((resolve, reject) => {
resolve('ok');
// reject('err');
})
//1.右侧为promise对象
// let result = await p;
//2.右侧为其他类型的数据
// let result = await 20;
//3.如果promise是失败的状态
try {
let result = await p;
console.log(result);
} catch (e) {
console.log(e);
}
}
main();
async和await的结合:
async function main() {
// let res = await new Promise((resolve, reject) => {
// resolve('521');
// })
let res = await 'ok';
console.log(res);
}
main();
- 发送Ajax请求:
function sendajax(url) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.responseText);
} else {
reject(xhr.status);
}
}
}
})
}
var btn = document.querySelector("button");
btn.addEventListener('click', async function () {
let duanzi = await sendajax('https://api.apiopen.top/getJoke');
console.log(duanzi);
})