一、指定回调和修改状态的执行顺序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>指定回调和修改状态执行顺序</title>
</head>
<body>
<script>
/*
改变状态和指定回调的执行顺序,谁先谁后?
--都有可能,正常情况是先指定回调函数再改变状态,但是也可以先改变状态再指定回调
如何先改变状态再指定回调?
1. 在执行器中直接调用resolve()/reject()
2. 延长更长时间才调用then()
什么时候才得到数据?
1. 如果先指定回调,当状态改变时,回调函数就会被调用,得到数据
2. 如果先改变状态,那当指定回调时,回调函数就会被调用,得到数据
*/
// 1. 先改变状态,后指定回调
let promise1 = new Promise((resolve, reject) => {
resolve("1-resolve-ok");
console.log("1-resolve-ok");
});
promise1.then((resolve) => {
console.log('2-then-resolve');
});
// 2. 先指定回调,后改变状态(注意是指定回调而不是执行回调)
let promise2 = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve("1-resolve-ok");
console.log("1-resolve-ok");
},1000);
});
promise2.then((resolve) => {
console.log('2-then-resolve');
});
</script>
</body>
</html>
二、then方法的返回值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>then方法的返回结果</title>
</head>
<body>
<script>
/*
then的返回结果,由then指定的回调函数执行的结果决定的
详细来说:
1. 如果抛出异常,新promise变为reject,reason为抛出的异常
2. 如果返回的是非promise的任意值,,新promise变为resolve,value为返回的值
3. 如果返回的是另一个新的promise,此promise的结果,就是新promise的结果
4. 默认状态'fullfilled',默认值undefined
*/
let promise = new Promise((resolve, reject) => {
resolve('ok')
});
let result = promise.then(value => {
console.log(value);
/*
1. 抛出异常
throw 'error';//promise,reject,'error';
result为:
Promise
[[Prototype]]: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: "error"
*/
//
/*
2. 返回非promise的值
return 123;
result为:
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: 123
*/
return new Promise((resolve,reject)=>{reject('error')});
/*
1. 返回Promise对象
result为:
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: "error"
*/
}, reason => {
console.log(reason);
})
console.log(result);// promise对象
</script>
</body>
</html>
三、Promise串联多个操作任务
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>promise串联多个操作任务</title>
</head>
<body>
<script>
/*
promise的then方法返回一个promise,可以看成then的链式调用
通过then的链式调用串联多个同步/异步任务
*/
let promise = new Promise((resolve, reject) => {
//resolve('ok');//同步
setTimeout(() => {//异步
resolve('1-ok');
}, 1000);
});
promise.then(value => {
return new Promise((resolve, reject) => {
resolve('2-ok');
})
}).then(value => {
console.log('3-ok', value);//2-ok
}).then(value => {
console.log('4-ok', value);//undefined
});
console.log(promise);
/*
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: "1-ok"
*/
</script>
</body>
</html>
四、异常穿透
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>异常穿透</title>
</head>
<body>
<script>
/*
promise异常穿透
1. 当使用promise的then链式调用时,可以在最后指定失败的回调
2. 前面任何操作出了异常,都会传到最后失败的回调中处理
中断promise链
1. 当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数
2. 办法:在回调函数中,返回一个pedding状态的promise对象
*/
let promise = new Promise((resolve, reject) => {
// setTimeout(() => {
// reject('error');
// }, 1000);
throw 'error';
});
let result = promise.then(value => {
console.log(111);
}, reason => {
console.log(reason);
return 456;
})//.then(value => {
// console.log(222);
// }).then(value => {
// console.log(333);
// })
.catch(reason => {
console.log(reason);
return 123;
}); // 按顺序执行,并最终进入到catch,不用每个then方法都写error的回调
console.log(result);
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('error')
}, 1000);
});
promise1.then(value => {
console.log(111);
return new Promise(() => { })// 返回pedding状态的promise对象,之后的then方法就不会执行了
}, reason => {
console.log(reason);
throw reason;
return new Promise(() => { })
}).then(value => {
console.log(222);
}).then(value => {
console.log(333);
}).catch(reason => {
console.log(reason);
});
</script>
</body>
</html>
五、async函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>async函数</title>
</head>
<body>
<script>
/*
1. async函数的返回值为一个promise对象
2. 对象的值由函数的返回值由async函数的返回值决定
3. async函数相当于promise的then方法
*/
async function main() {
// 1. 返回非promise的值
// return 123;
/*
res:
Promise
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: 123
*/
// 2. 返回promise值
return new Promise((resolve, reject) => {
// resolve('ok');
/*
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: "ok"
*/
reject('error');
/*
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: "error"
*/
// 3. 抛出异常
// throw 'oh no';
/*
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: 'oh no'
*/
})
}
let res = main();
console.log(res)
/*
main函数没有返回值:
res:
Promise
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined
*/
</script>
</body>
</html>
六、await表达式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>await表达式</title>
</head>
<body>
<script>
/*
1. await右侧的表达式一般为promise对象,但也可以为其他值
2. 如果是promise对象,则await返回的是promise成功的值
3. 如果表达式的是其他值,直接将此值作为await的返回值
注意:
1. await必须写在async函数中,但是async函数中可以没有await
2. 如果await的promise失败了,就会抛出异常,需要通过try...catch捕获处理
*/
async function main() {
let p = new Promise((resolve, reject) => {
// resolve('ok');
reject('error');
});
// 1. 非promise
let res1 = await 123;
console.log(res1);//123
// 2. 为promise -成功
// let res = await p;
// console.log(res);//ok
// 3. 为promise -失败
try {
let res2 = await p;
} catch (e) {
console.log(e);//error
}
}
main();
</script>
</body>
</html>
七、async和await的实践-读取文件
// node filename.js
const fs = require('fs');
const util = require('util');
const mineReadFile = util.promisify(fs.readFile)
// 读取文件
// fs.readFile('./resource/readme.txt', (err1, data1) => {
// if (err1) throw err1;
// fs.readFile('./resource/txt.txt', (err2, dada2) => {
// if (err2) throw err2;
// console.log(data1 + dada2);
// })
// });
async function main() {
try {
let data1 = await mineReadFile('./resource/readme.xt');
let data2 = await mineReadFile('./resource/txt.txt');
console.log(data1 + data2);
} catch (e) {
console.log(e.code);
}
}
main();
八、async和await的实践-ajax请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>async与await</title>
</head>
<body>
<button id="btn">点击发送</button>
<script>
function sendAjax(url, type) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(type, url);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
}
});
}
// sendAjax('http://localhost:2000/server', 'get').then((
// data) => { console.log(data) },
// (err) => { console.log(err) }
// );
const btn = document.getElementById('btn');
btn.addEventListener('click', async function () {
// 发送
let res = await sendAjax('http://localhost:2000/server', 'get');
console.log(res);
})
</script>
</body>
</html>