Promise
、async/await
的使用
目录
Promise
async/await
Promise
什么是 Promise
?
Promise
是异步编程的一种解决方案,它代表了一个异步操作的最终结果。它是一个对象,用来传递异步操作的消息,而不是直接传递结果。
Promise
提供统一的 API
,各种异步操作都可以用同样的方法进行处理,并提供统一的接口。Promise
也有三种状态:
Pending
(等待中):初始状态,既没有完成也没有失败。Fulfilled
(已完成):操作成功完成。Rejected
(已失败):操作失败。
Promise
的特点
- 对象的状态不受外界影响。Promise 实例代表一个异步操作,有三种状态,分别是
Pending
(等待中)、Fulfilled
(已完成)和Rejected
(已失败)。只有异步操作的结果,才会改变 Promise 的状态。 - 一旦状态改变,就不会再变,任何时候都可以得到这个结果。
Promise
实例代表的异步操作,一旦异步操作完成,就不会再变,任然是Pending
状态。 Promise
对象的then
方法是定义在原型上面的,可以把多个Promise
实例进行链式调用。Promise
对象的catch
方法是定义在原型上面的,可以捕获Promise
实例中发生的错误。Promise
对象的finally
方法是定义在原型上面的,不管Promise
实例最后状态如何,都会执行指定的回调函数。Promise
实例的构造函数接受一个执行器函数,该函数的两个参数分别是resolve
和reject
。resolve
用于将Promise
对象的状态从Pending
变为Fulfilled
,reject
用于将Promise
对象的状态从Pending
变为Rejected
。
Promise
的基本用法
// 创建一个Promise实例
const promise = new Promise((resolve, reject) => {
// 异步操作成功时调用resolve函数
resolve('success');
// 异步操作失败时调用reject函数
reject('error');
});
// 处理Promise对象的状态改变
promise.then(value => {
console.log(value); // "success"
}).catch(error => {
console.log(error); // "error"
});
Promise
的链式调用
// 创建Promise实例
const promise1 = new Promise((resolve, reject) => {
resolve('success1');
});
// 链式调用
promise1.then(value => {
console.log(value); // "success1"
return 'success2';
}).then(value => {
console.log(value); // "success2"
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success3');
}, 1000);
});
}).then(value => {
console.log(value); // "success3"
}).catch(error => {
console.log(error);
});
Promise
的错误处理
// 创建Promise实例
const promise = new Promise((resolve, reject) => {
throw new Error('error');
});
// 处理Promise对象的状态改变
promise.then(value => {
console.log(value);
}).catch(error => {
console.log(error); // "error"
});
Promise
的 finally
方法
finally
方法的作用
finally
方法用于指定不管 Promise
实例最后状态如何,都会执行指定的回调函数。
finally
方法的用法
// 创建Promise实例
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success');
}, 1000);
});
// 处理Promise对象的状态改变
promise.then(value => {
console.log(value); // "success"
}).catch(error => {
console.log(error);
}).finally(() => {
console.log('finally');
});
Promise
的状态变化
const promise = new Promise((resolve, reject) => {
// 异步操作成功时调用resolve函数
resolve('success');
// 异步操作失败时调用reject函数
reject('error');
});
// 处理Promise对象的状态改变
promise.then(value => {
console.log(value); // "success"
}).catch(error => {
console.log(error); // "error"
});
Promise
的缺点
- 无法取消
Promise
,一旦新建就会立即执行,无法中途取消。 - 如果不设置回调函数,
Promise
内部抛出的错误,不会反应到外部。 - 当处于
Pending
状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。 - 如果不设置回调函数,Promise 对象会一直处于
Pending
状态,导致程序运行阻塞。
async/await
async/await
是什么?
async/await
是 ECMAScript 2017
引入的异步编程语法,它是 Promise
的语法糖。
async/await
让异步操作变得更加方便,让代码更简洁,更易读。
async/await
就是 Generator
函数和 Promise
的组合。
async/await的特点
- 内置执行器。
async/await
关键字会自动执行Generator
函数,并返回一个Promise
对象。 - 更好的语义。
async/await
更容易理解和编写。 - 更广的适用性。
async/await
适用于大多数异步操作,不仅仅局限于Generator
函数。 - 错误处理。async/await 可以捕获并处理
Promise
对象的错误。
async/await
的基本用法
async function hello() {
return 'hello world';
}
hello().then(value => {
console.log(value); // "hello world"
});
async/await
的链式调用
async function hello() {
return 'hello';
}
async function world() {
return 'world';
}
async function helloWorld() {
const helloValue = await hello();
const worldValue = await world();
return `${helloValue} ${worldValue}`;
}
helloWorld().then(value => {
console.log(value); // "hello world"
});
async/await
的错误处理
async function hello() {
throw new Error('error');
}
hello().then(value => {
console.log(value);
}).catch(error => {
console.log(error); // "error"
});
async/await
的 finally
方法
async function hello() {
return 'hello';
}
async function world() {
return 'world';
}
async function helloWorld() {
const helloValue = await hello();
const worldValue = await world();
return `${helloValue} ${worldValue}`;
}
helloWorld().then(value => {
console.log(value); // "hello world"
}).finally(() => {
console.log('finally');
});
async/await
的缺点
- 无法取消
async/await
,一旦开始就会执行,无法中途取消。 - 无法获取函数执行的进度。
- 错误处理不如
Promise
友好。 - 调试不如
Generator
函数友好。
Generator
函数
什么是 Generator
函数?
Generator
函数是一种异步编程解决方案,它是一种特殊的函数,它返回一个可迭代对象(Iterator
)。
Generator
函数是一个状态机,封装了多个内部状态。
Generator
函数运行后,返回一个遍历器对象,可以依次遍历 Generator
函数内部的每一个状态。
Generator
函数可以暂停函数执行的位置,返回后续的执行结果。
Generator
函数可以让异步操作更加方便。
Generator
函数的特点
Generator
函数是一个状态机,封装了多个内部状态。Generator
函数运行后,返回一个遍历器对象,可以依次遍历Generator
函数内部的每一个状态。Generator
函数可以暂停函数执行的位置,返回后续的执行结果。Generator
函数可以暂停函数执行的位置,返回后续的执行结果。Generator
函数可以方便地实现异步操作。
Generator
函数的基本用法
function* helloWorld() {
yield 'hello';
yield 'world';
}
const hw = helloWorld();
hw.next().value; // "hello"
hw.next().value; // "world"
hw.next().value; // undefined
Generator
函数的错误处理
function* helloWorld() {
yield 'hello';
throw new Error('error');
yield 'world';
}
const hw = helloWorld();
hw.next().value; // "hello"
hw.next().value; // Uncaught Error: error
Generator
函数的 yield*
语句
yield*
语句可以将另一个 Generator
函数的执行结果,赋值给当前 Generator
函数的执行结果。
function* hello() {
yield 'hello';
}
function* world() {
yield 'world';
}
function* helloWorld() {
yield* hello();
yield* world();
}
const hw = helloWorld();
hw.next().value; // "hello"
hw.next().value; // "world"
hw.next().value; // undefined
Generator
函数的 return
语句
Generator
函数如果使用 return
语句,函数执行结束,且返回给定的值。
function* helloWorld() {
yield 'hello';
return 'world';
}
const hw = helloWorld();
hw.next().value; // "hello"
hw.next().value; // "world"
hw.next().value; // undefined
Generator
函数的 throw
语句
Generator
函数如果使用 throw
语句,函数会抛出错误,并中断执行。
function* helloWorld() {
yield 'hello';
throw new Error('error');
yield 'world';
}
const hw = helloWorld();
hw.next().value; // "hello"
hw.next().value; // Uncaught Error: error
hw.next().value; // undefined
Generator
函数的 next
方法
Generator
函数的 next
方法可以手动控制 Generator
函数的执行。
function* helloWorld() {
try {
yield 'hello';
yield 'world';
} catch (e) {
console.log(e);
}
}
const hw = helloWorld();
hw.next().value; // "hello"
hw.next().value; // "world"
hw.next(); // { value: undefined, done: true }
Generator
函数的 for...of
循环
Generator
函数可以通过 for...of
循环来遍历执行。
function* helloWorld() {
yield 'hello';
yield 'world';
}
for (let value of helloWorld()) {
console.log(value);
}
// "hello"
// "world"
Generator
函数的缺点
Generator
函数只能使用for...of
循环来遍历,无法使用next
方法来手动控制执行。Generator
函数内部只能使用yield
语句,不能使用return
语句返回值。Generator
函数内部的错误无法被捕获,只能在函数外部使用try...catch
语句捕获。Generator
函数没有自己的this
,所以无法用作类的构造函数。Generator
函数的执行必须靠执行器,所以不适合在服务端使用。
async/await
和 Generator
函数的区别
async/await
和 Generator
函数的区别主要有以下几点:
async/await
是Promise
的语法糖,Generator
函数是Iterator
的语法糖。async/await
更简洁,更易读,内置执行器,更方便处理错误。async/await
适用于大多数异步操作,不仅仅局限于Generator
函数。async/await
无法取消,Generator
函数可以取消。async/await
无法获取函数执行的进度,Generator
函数可以获取函数执行的进度。async/await
错误处理不如Promise
友好,Generator
函数可以捕获并处理错误。async/await
调试不如Generator
函数友好,Generator
函数可以调试。async/await
无法在服务端使用,Generator
函数可以在服务端使用。
async/await
和 Promise
的区别
async/await
和 Promise
的区别主要有以下几点:
async/await
是Promise
的语法糖。async/await
更简洁,更易读,内置执行器,更方便处理错误。async/await
适用于大多数异步操作,不仅仅局限于Promise
。async/await
无法取消,Promise
可以取消。async/await
无法获取函数执行的进度,Promise
可以获取函数执行的进度。async/await
错误处理不如Promise
友好,Promise
可以捕获并处理错误。async/await
调试不如Promise
友好,Promise
可以调试。async/await
无法在服务端使用,Promise
可以在服务端使用。
async/await
和 Generator
函数的选择
一般来说,如果需要处理多个异步操作,建议使用 async/await
,因为它更简洁,更易读,而且内置执行器,更方便处理错误。
如果只需要处理单个异步操作,建议使用 Promise
,因为它提供了统一的 API
,各种异步操作都可以用同样的方法进行处理,并提供统一的接口。
如果需要处理多个异步操作,并且需要处理错误,建议使用 async/await
,因为它更简洁,更易读,而且内置执行器,更方便处理错误。
Promise
和 async/await
的选择
一般来说,如果需要处理多个异步操作,建议使用 Promise
,因为它提供了统一的 API
,各种异步操作都可以用同样的方法进行处理,并提供统一的接口。
如果只需要处理单个异步操作,建议使用 async/await
,因为它更简洁,更易读,而且内置执行器,更方便处理错误。
如果需要处理多个异步操作,并且需要处理错误,建议使用 Promise
,因为它提供了统一的 API
,各种异步操作都可以用同样的方法进行处理,并提供统一的接口。