<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button οnclick="test">点击</button>
</body>
</html>
<script>
// Promise 是 JavaScript 中的一个对象,用于异步计算的一个解决方案,以更易于管理和维护的方式处理异步操作,避免了传统的回调地狱(callback hell)问题。Promise代表一个现在、将来或永远可能可用,或者永远不会可用的值。
// 基本概念
// 状态:Promise有三种状态——pending(等待中)、fulfilled(已成功)和rejected(已失败)。状态一旦从pending变为fulfilled或rejected,就不会再改变。
// 构造函数:创建Promise实例需要通过new Promise(executor),其中executor是一个函数,接受两个参数resolve和reject,分别在异步操作成功和失败时被调用。
// 在JavaScript的世界中,所有代码都是单线程执行的。
// 由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现:
function add(){
console.log("我要过一会儿在执行add函数")
}
console.log('before setTimeout()');
setTimeout(add,3000)// 3秒钟后调用add函数
console.log('after setTimeout()');
// 这种情况则是体现异步的过程,边执行边等待
// 写一个异步函数
// 生成一个0-2之间的随机数,如果小于1,则等待一段时间后返回成功,否则返回失败:
function test(resolve, reject) {
var timeOut = Math.random() * 2;
console.log('set timeout to: ' + timeOut + ' seconds.');
setTimeout(function () {
if (timeOut < 1) {
console.log('call resolve()...');
resolve('200 OK');
}
else {
console.log('call reject()...');
reject('timeout in ' + timeOut + ' seconds.');
}
}, timeOut * 1000);
}
// resolve, reject这里是两个函数作为参数,
// 下面是在test()函数中调用的函数,在使用Promise对象时需要将其注释掉
// test(
// function (result) { // 成功的回调
// console.log('Success:', result);
// //如果timeOut<1, console.log('call resolve()...');,我们将调用resolve('200 OK'),此时result=200 OK
// },
// function (error) { // 失败的回调
// console.error('Error:', error);
// //如果timeOut!=1,console.log('call reject()...');我们将调用reject('timeout in ' + timeOut + ' seconds.')。此时error=timeout in timeOut seconds.
// }
// );
// 可以看出,test()函数只关心自身的逻辑,并不关心具体的resolve和reject将如何处理结果。
// 有了执行函数,我们就可以用一个Promise对象来执行它,并在将来某个时刻获得成功或失败的结果
// 链式调用:通过.then()和.catch()方法可以进行链式调用,处理Promise的结果或错误。
var p1 = new Promise(test);
var p2 = p1.then(function (result) {
console.log('成功:' + result);
});
var p3 = p2.catch(function (reason) {
console.log('失败:' + reason);
});
// 或者
// p1.then(function (result) {
// console.log('成功:' + result);
// }).catch(function (reason) {
// console.log('失败:' + reason);
// });
// 或者直接用promise对象进行异步操作
// let promise = new Promise((resolve, reject) => {
// // 异步操作
// });
// resolve: 当异步操作成功完成时调用的函数,用来改变Promise的状态为fulfilled(已成功),并将操作的结果作为参数传递出去。
// reject: 当异步操作失败或者遇到错误时调用的函数,用来改变Promise的状态为rejected(已失败),并将错误原因作为参数传递出去。
// 完整示例代码
// new Promise(function (resolve, reject) {
// log('start new Promise...');
// var timeOut = Math.random() * 2;
// log('set timeout to: ' + timeOut + ' seconds.');
// setTimeout(function () {
// if (timeOut < 1) {
// log('call resolve()...');
// resolve('200 OK');
// }
// else {
// log('call reject()...');
// reject('timeout in ' + timeOut + ' seconds.');
// }
// }, timeOut * 1000);
// }).then(function (r) {
// log('Done: ' + r);
// }).catch(function (reason) {
// log('Failed: ' + reason);
// });
// Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。
// 要串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:
// job1.then(job2).then(job3).catch(handleError);
// 0.5秒后返回input*input的计算结果:
// function multiply(input) {
// return new Promise(function (resolve, reject) {
// log('calculating ' + input + ' x ' + input + '...');
// setTimeout(resolve, 500, input * input);
// });
// }
// // 0.5秒后返回input+input的计算结果:
// function add(input) {
// return new Promise(function (resolve, reject) {
// log('calculating ' + input + ' + ' + input + '...');
// setTimeout(resolve, 500, input + input);
// 因此,当resolve函数在500毫秒后被调用时,它会接收到一个参数,该参数是input值的两倍(因为input + input)。
// });
// }
// var p = new Promise(function (resolve, reject) {
// log('start new Promise...');
// resolve(123);
// });
// p.then(multiply)
// .then(add)
// .then(multiply)
// .then(add)
// .then(function (result) {
// log('Got value: ' + result);
// });
// setTimeout可以看成一个模拟网络等异步执行的函数。现在,我们把上一节的AJAX异步执行函数转换为Promise对象,看看用Promise如何简化异步处理:
// ajax函数将返回Promise对象:
// function ajax(method, url, data) {
// var request = new XMLHttpRequest();
// return new Promise(function (resolve, reject) {
// request.onreadystatechange = function () {
// if (request.readyState === 4) {
// if (request.status === 200) {
// resolve(request.responseText);
// } else {
// reject(request.status);
// }
// }
// };
// request.open(method, url);
// request.send(data);
// });
// }
// var log = document.getElementById('test-promise-ajax-result');
// var p = ajax('GET', '/api/categories');
// p.then(function (text) { // 如果AJAX成功,获得响应内容
// log.innerText = text;
// }).catch(function (status) { // 如果AJAX失败,获得响应代码
// log.innerText = 'ERROR: ' + status;
// });
// 有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用Promise.race()实现:
// var p1 = new Promise(function (resolve, reject) {
// setTimeout(resolve, 500, 'P1');
// });
// var p2 = new Promise(function (resolve, reject) {
// setTimeout(resolve, 600, 'P2');
// });
// Promise.race([p1, p2]).then(function (result) {
// console.log(result); // 'P1'
// });
// 由于p1执行较快,Promise的then()将获得结果'P1'。p2仍在继续执行,但执行结果将被丢弃。
// 如果我们组合使用Promise,就可以把很多异步任务以并行和串行的方式组合起来执行。
</script>