本文并不提供 Promise 和 async 函数的用法说明, 仅尝试通过简单的示例代码对 Promise 和 async 函数的概念和本质作简单梳理.
Promise 和 async 函数是为异步而生, 但是, 如果将它们和异步划等号, 可能就有问题了.
先说 Promise
定义 promise
- // 定义 promise
- const promise = new Promise((resolve, reject) => {
- console.log('promise start');
- // 用一个 for 循环简单模拟一下大数据量处理
- for (let index = 0; index <5; index++) {
- console.log('promise process' + index);
- }
- console.log('promise end');
- })
- console.log('1');
- // 按照惯例, then 一下
- promise.then(()=>{console.log('Promise done')});
- console.log('2');
运行结果:
- promise start
- promise process 0
- promise process 1
- promise process 2
- promise process 3
- promise process 4
- promise end
- 1
- 2
在这个示例代码中, 定义 Promise 的代码在定义时就已经同步执行了, 后面的 then 调用没有任何输出.
- A:"说明什么? 说明 Promise 不是异步的, 它的定义和执行都不是异步的!"
- B:"你胡说, 你连 resolve 都没用!"
加入 resolve
- const promise = new Promise((resolve, reject) => {
- console.log('promise start');
- for (let index = 0; index <5; index++) {
- console.log('promise process' + index);
- }
- // 用 resolve 抛出一个值
- resolve('promise done');
- console.log('promise end');
- })
- console.log('1');
- // then 的回调函数中接到 resolve 抛出的值并输出到控制台
- promise.then((v)=>{console.log(v)});
- console.log('2');
运行结果:
- promise start
- Promise0
- Promise1
- Promise2
- Promise3
- Promise4
- promise end
- 1
- 2
- promise done
- B:"异步了吧? 异步了吧?'promise done'在 2 后面出来的."
- A:"整个 promise 执行过程是同步的, 把返回值异步出来, 顶个 X 用!"
- B:"......"
B:"我想起来了, 阮大侠说:"Promise 只是个异步操作容器 ", 所以你要在 Promise 中装个异步操作进去才行!"
塞个异步操作
- const promise = new Promise((resolve, reject) => {
- console.log('promise start');
- // 这个 setTimeout 就是塞进来的异步操作
- setTimeout(()=>{
- // 原来的大数据量处理语句移到 setTimeout 中来
- for (let index = 0; index <5; index++) {
- console.log('Promise' + index);
- }
- // 原来的结果返回语句也移到 setTimeout 中来
- resolve('promise done');
- },1000);
- console.log('promise end');
- })
运行结果:
- promise start
- promise end
- 1
- 2
- Promise0
- Promise1
- Promise2
- Promise3
- Promise4
- promise done
- B:"异步了吧? 异步了吧? 整个业务逻辑都是在 2 后面出来的."
- A:"是异步了, 但是 setTimeout 本身就执行了一个异步操作, 干嘛要多此一举的把它塞进 Promise 里呢?"
- B:"......"
为什么要用 Promise
我们在异步调用时经常会遇到 "后一个异步调用的参数是前一个异步调用的结果" 的情况, 传统方式写出来是这样:
- a(参数, function(){
- b(result-from-a,function(){
- //.....
- })
- })
a 和 b 嵌套起来了, 如果关联关系更多, 可能会出现这种情况:
- a(参数, function(){
- b(result-from-a,function(){
- c(result-from-b,function(){
- d(result-from-c,function(){
- e(result-from-d,function(){
- //.....
- })
- })
- })
- })
- })
这还只是非常理想的单一数据获取情况下的嵌套, 如果有分支嵌套再加上异常处理, 那干脆能乱成一锅粥. 这就是那个有名的 "回调地狱".
怎么破? Promise!
- a.then((result-from-a)=>{
- return b(result-from-a);
- })
- .then((result-from-b)=>{
- return c(result-from-b);
- })
- .then((result-from-c)=>{
- return d(result-from-c);
- })
- .then((result-from-d)=>{
- return e(result-from-d);
- })
- .then((result-from-e)=>{
- console.log(result-from-e);
- })
- .catch((error)=>{
- console.log(error);
- })
这样舒心多了吧?
所以, Promise 是个包装器, 把异步操作包起来, 以更易读更有条理更符合人类思维习惯的方式让广大程序猿 (嫒) 来写异步代码. 如果抛开异步操作使用 Promise 就是耍流氓.
要点是: Promise 是用来包装异步操作的
再看 async 函数
- B:"async, 就是异步的意思, async 函数, 当然就是异步执行的函数了. 这个不存在二义性吧?"
- A:"这个......, 咱们用代码说话......"
初探 async 函数
- // 定义 async 函数
- async function asynFunction(){
- console.log('asynFunction begin');
- // 还是用一个 for 循环代表大数据量处理
- for (let index = 0; index <5; index++) {
- console.log('asynFunction process' + index);
- }
- console.log('asynFunction end');
- }
- console.log('1');
- // 调用 async 函数
- asynFunction();
- console.log('2');
执行结果:
- 1
- asynFunction begin
- asynFunction process 0
- asynFunction process 1
- asynFunction process 2
- asynFunction process 3
- asynFunction process 4
- asynFunction end
- 2
- B:"这个......, 异步函数没有异步执行? 会不会是什么地方写错了?"
- A:"哈哈, 加点东西给你看看"
await 出场
- async function asynFunction(){
- console.log('asynFunction begin');
- // 加入 await
- await 'async go!';
- for (let index = 0; index < 5; index++) {
- console.log('asynFunction process' + index);
- }
- console.log('asynFunction end');
- }
- console.log('1');
- // 调用 async 函数
- asynFunction();
- console.log('2');
执行结果:
- 1
- asynFunction begin
- 2
- asynFunction process 0
- asynFunction process 1
- asynFunction process 2
- asynFunction process 3
- asynFunction process 4
- asynFunction end
- B:"从 await 开始, 后面语句都异步了? 难道 await 表示异步开始的意思?......"
- B:"不对啊, wait 是等待的意思, await 明明是用来等待异步执行结果的, 在这里怎么变成异步开始的标志了?......"
A:"你说对了, await 是用来等待异步执行结果的. 但是 await 在使用时, 后面需要跟一个 Promise 对象, 如果不是, 会被转为 Promise 对象, 如上面的 await'async go!'相当于如下代码:
- await new Promise((resolve, reject) => {
- resolve('async go!');
- })
- A:"所以, await 并不是异步开始的标志, 而是因 await 对异步执行的等待, 导致 await 之后语句延后执行. 我们再写段代码看看......"
引入 Promise
- function a(arg){
- return new Promise((resolve, reject) => {
- resolve(arg);
- })
- }
- function b(arg){
- return new Promise((resolve, reject) => {
- resolve('你好,' + arg);
- })
- }
- async function asynFunction(){
- var aResult = await a('北京');
- var bResult = await b(aResult);
- console.log(bResult);
- }
- console.log('1');
- asynFunction();
- console.log('2');
执行结果:
1
2
你好, 北京
- A:"当然, 我们往往需要通过 async 函数返回需要的数据......"
- function a(arg){
- return new Promise((resolve, reject) => {
- resolve(arg);
- })
- }
- function b(arg){
- return new Promise((resolve, reject) => {
- resolve('你好,' + arg);
- })
- }
- async function asynFunction(){
- var aResult = await a('北京');
- var bResult = await b(aResult);
- // 返回执行结果
- return bResult;
- }
- console.log('1');
- // 需要在 then()方法中获取执行结果, 原因是 async 函数的返回值同样会被包装成 Promise 对象
- asynFunction().then((v)=>{console.log(v)});
- console.log('2');
执行结果:
1
2
你好, 北京
async 函数其实也是一个包装器, async 和 await 配合, 包装的是 Promise, 与 Promise 相比易读性更好, 更加符合代码语义.
要点是: async 函数是用来包装 Promise 的
总结
Promise 是用来包装异步操作的, 所以仅仅包含同步代码它是异步不了滴.
Promise 把异步操作包装起来, 是为了让你的异步代码看起来更直观更优雅.
async 函数是用来包装 Promise 的, 所以仅仅包含同步代码它也是异步不了滴.
async 函数把 Promise 包装起来, 是为了让你的异步代码看起来比 Promise 还要直观还要
优雅, 能够做到望文生义......
来源: http://www.jianshu.com/p/dd9d35107f48