一、Promise 是什么?
Promise 是一个用于绑定异步操作与回调函数的对象,让代码更易读且更合理。
1、简单实例
<!-- index.html -->
<!DOCTYPE html>
<html lang='zh-CN'>
<head>
<meta charset="utf-8">
<title>异步调用</title>
<script>
let myFirstPromise = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("成功!");
// reject("失败");
}, 2500);
});
myFirstPromise
.then((successMessage) => {
console.log(successMessage);
})
.catch((errorMessage) => {
console.log(errorMessage);
});
</script>
</head>
<body>
<h1>打开 console 看输出结果!</h1>
</body>
</html>
二、语法说明
1、运行规则
不同于传统的回调, then 关联的函数,会在异步操作完成后执行;如果有多个 then,那么也会依次调用,除非其中有调用 reject 跳转到 catch 。
2、创建 Promise 对象
通过 new 来创建 Promise 对象,当异步操作成功后调用 resolve 来改变 Promise对象的状态;失败后就调用 reject 。
const myFirstPromise = new Promise((resolve, reject) => {
// 做一些异步操作,最终会调用下面两者之一:
//
// resolve(someValue);
// 或
// reject("failure reason");
});
3、函数拥有 Promise 功能
函数想要拥有 Promise 功能,只需让其返回一个 Promise对象 即可。
function myAsyncFunction(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = () => resolve(xhr.responseText);
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
});
};
4、不使用回调
对 setTimeout 进行 Promise 封装,代码易读且包含异常处理等情况,步骤如下:
// 1、过去是用方法
setTimeout(() => saySomething("10 seconds passed"), 10000);
// 2、用 Promise 封装
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
// 3、以后用这种方式
wait(10000).then(() => saySomething("10 seconds")).catch(failureCallback);
三、静态函数
1、Promise.resolve()
返回一个已处理的 Promise 对象。
Promise.resolve("Success").then(function(value) {
console.log(value); // "Success"
}, function(value) {
// 不会被调用
});
2、Promise.reject()
返回一个带有拒绝原因的 Promise
对象。
Promise.reject(new Error('fail')).then(function() {
// not called
}, function(error) {
console.error(error); // Stacktrace
});
3、Promise.all()
等待所有 Promise 对象执行完毕,如果其中任何一个产生 reject ,那么会立即返回。
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
4、Promise.race()
同时等待多个 Promise 对象,但只采用其中最先返回的 Promise 对象。
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster
});
// expected output: "two"
四、async / await
1、概念说明
async / await 建立在 Promise 之上,使异步代码更易于编写和阅读,他们是 ECMAScript 2017 JavaScript版本的新语法。
async 怎么使用?
函数声明之前加上 async 关键字,就变成了异步函数了,返回值为promise。
let hello = async () => { return "Hello" };
let hello = async function() { return "Hello" };
hello();
await 怎么使用?
await 只有用于异步函数才起作用,基于 promise 的函数之前加上 await ,代码会在此行暂停,直到 promise 操作完成,当然其他代码可以继续执行。
async function hello() {
return greeting = await Promise.resolve("Hello");
};
hello().then(alert);
2、async / await 替代 Promise
三种不同方式,实现相同的功能。
- Promise 的写法
fetch('coffee.jpg')
.then(response => response.blob())
.then(myBlob => {
let objectURL = URL.createObjectURL(myBlob);
let image = document.createElement('img');
image.src = objectURL;
document.body.appendChild(image);
})
.catch(e => {
console.log('There has been a problem with your fetch operation: ' + e.message);
});
- async / await 的写法
async function myFetch() {
let response = await fetch('coffee.jpg');
let myBlob = await response.blob();
let objectURL = URL.createObjectURL(myBlob);
let image = document.createElement('img');
image.src = objectURL;
document.body.appendChild(image);
}
myFetch()
.catch(e => {
console.log('There has been a problem with your fetch operation: ' + e.message);
});
- 混合使用
async function myFetch() {
let response = await fetch('coffee.jpg');
return await response.blob();
}
myFetch().then((blob) => {
let objectURL = URL.createObjectURL(blob);
let image = document.createElement('img');
image.src = objectURL;
document.body.appendChild(image);
})
.catch((e) =>
console.log(e)
);
3、缺陷修正
- 下面代码完成了同步,但增加了等待时间。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Demonstration of slow async/await</title>
</head>
<body>
<script>
function timeoutPromise(interval) {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve("done");
}, interval);
});
};
async function timeTest() {
await timeoutPromise(3000);
await timeoutPromise(3000);
await timeoutPromise(3000);
}
let startTime = Date.now();
timeTest().then(() => {
let finishTime = Date.now();
let timeTaken = finishTime - startTime;
alert("Time taken in milliseconds: " + timeTaken);
})
</script>
</body>
</html>
- 简单修改上面,即可提高性能
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Demonstration of fast async/await</title>
</head>
<body>
<script>
function timeoutPromise(interval) {
return new Promise((resolve, reject) => {
setTimeout(function () {
resolve("done");
}, interval);
});
};
async function timeTest() {
const timeoutPromise1 = timeoutPromise(3000);
const timeoutPromise2 = timeoutPromise(3000);
const timeoutPromise3 = timeoutPromise(3000);
await timeoutPromise1;
await timeoutPromise2;
await timeoutPromise3;
}
let startTime = Date.now();
timeTest().then(() => {
let finishTime = Date.now();
let timeTaken = finishTime - startTime;
alert("Time taken in milliseconds: " + timeTaken);
})
</script>
</body>
</html>
五、其他异步操作
1、setTimeout
setTimeout :在指定时间后执行一次;
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<title>Person greeter app</title>
</head>
<body>
<script>
let myGreeting = setTimeout(function () {
alert('Hello, Mr. Universe!');
}, 2000)
// 在超时前关闭计时器
// clearTimeout(myGreeting);
</script>
</body>
</html>
2、setInterval
在指定的时间间隔,不停重复运行。
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<title>Simple setInterval clock</title>
<style>
p {
font-family: sans-serif;
}
</style>
</head>
<body>
<p class="clock"></p>
<script>
function displayTime() {
let date = new Date();
let time = date.toLocaleTimeString();
document.querySelector('.clock').textContent = time;
}
const createClock = setInterval(displayTime, 1000);
// 关闭 Interval
// clearInterval(myInterval);
</script>
</body>
</html>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。