Promise≠异步,async函数≠异步

本文并不提供Promiseasync函数的用法说明,仅尝试通过简单的示例代码对Promiseasync函数的概念和本质作简单梳理。

Promiseasync函数是为异步而生,但是,如果将它们和异步划等号,可能就有问题了。
查看原文

先说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还要直观还要
优雅,能够做到望文生义......

本文的初衷其实是希望大家不要望文生义......>_<

题外话

  • 为什么示例中的异步操作都在主线代码之后执行?
    因为event-loop,不了解点这里(密码:yc3r)
  • 为什么Promise示例中总是有一个reject
    当发生错误、异常,未获取到数据等情况时会用到它,不了解点这里
  • 为什么async函数中的await可以等待
    因为它们是generator的语法糖,不了解点这里
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,194评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,058评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,780评论 0 346
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,388评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,430评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,764评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,907评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,679评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,122评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,459评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,605评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,270评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,867评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,734评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,961评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,297评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,472评论 2 348

推荐阅读更多精彩内容