博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
你不知道的JavaScript :Promise 与 Async/Await
阅读量:6606 次
发布时间:2019-06-24

本文共 7322 字,大约阅读时间需要 24 分钟。

前言

对于JavaScript这门语言,其实我更喜欢称它为ECMAScript,从一开始我们就已经涉及到异步编程,但是多数JavaScript开发者从来没有认真思考过自己程序中的异步,到底是怎么实现的,以及为什么会出现。但是由于开发者对JavaScript的需求和项目的复杂程度日渐扩大,特别是对异步的管理越来越令人痛苦,这一切导致我们迫切需要更加强大、更加合理的异步方法,帮我们管理异步的状态。

开始

在JavaScript异步编程历史上,我认为一共出现了三种异步编程方式

  • 回调
  • Promise
  • Async/Await

由于我不想回忆起很久以前,被回调地狱支配的恐惧,就跳过回调这一块,读者们自行了解(篇幅有限)

(PS:好吧,new Date() --> Sat May 19 2018 23:55:17 GMT+0800 (中国标准时间),写完洗洗睡吧)

Promise

什么是Promise

Promise是一种范式。在这里扯一句:回调是将我们封装的回调函数交给第三方(甚至可能是外部代码),紧接着我们期待它能够调用我们封装的回调函数。那么Promise就是不把自己的程序传递给第三方,而是第三方给我们提供此任务何时结束,然后由我们自己决定下一步做什么

设想一个场景,今天早上,我去买早餐,到了一个快餐店,
点了一个汉堡
做了一次请求),我就在收银台上
支付了这个汉堡的价格
类似于参数的传递),但是我并没有立即得到这个汉堡,而是拿到了一个订单号,这个时候我就只需要坐着等待小姐姐叫到我的订单号(
这个时候已经产生了一个Promise),在这个中间等待的时间,我们可以做一些其他的事情,比如打电话、玩儿手机、谈工作等等......(
这就是合理利用中间的空隙时间,在js的异步中也可以完全体现,但不在本文的探讨范围内),直到小姐姐叫到XX号码的好了(
一个Promise执行结束),
结果一般有两种,要么是
汉堡做好了
Promise中的resolve()中设置的值),要么是
汉堡卖完了(Promise中的reject()中设置的值),这时我就需要考虑换其他食物了。假设汉堡做好了,我再过去拿我的汉堡,拿到过后,我可以自行选择吃掉它或者是扔掉它(当然这是不可能的)(
这就体现了具体怎么实现的决定权在我们)
这个例子我觉得还是很形象的,哈哈哈。

如何创建并使用一个Promise

首先我先告诉你Promise的决议结果resovle完成reject拒绝

// -----------------------> Promise 的创建与使用  function creat_promise () {    return new Promise((resolve, reject) => {      resolve(42)    })  }  function use_promise () {    const a_promise = creat_promise()    a_promise.then(res => console.log(res))  }  use_promise()

Promise的高级使用方法

当你看到这一节时,需要用到自定义的模拟数据请求类

// api.js// 定义初始数据const users = [  { id: 1, name: 'jack', year: 12, grade: 1 },  { id: 2, name: 'john', year: 12, grade: 1 },  { id: 3, name: 'winer', year: 12, grade: 2 }]// user的father,根据child链接const fathers = [  {id: 11, child: 'jack', name: 'jack_father'},  {id: 22, child: 'john', name: 'john_father'},  {id: 33, child: 'winer', name: 'winer_father'}]class Api {  // 根据id获取一个User对象的Promise  getUserById (id, request_time = 1000, fn = function () {}) {    return new Promise((resolve, reject) => {      setTimeout(() => {        const user = users.find(item => {          return item.id === id        })        fn()        resolve(user)      }, request_time)    })  }  // 根据grade获取一个User对象列表的Promise  getUsersByGrade (grade) {    return new Promise((resolve, reject) => {      setTimeout(() => {        const _users = users.filter(item => {          return item.grade === grade        })        resolve(_users)      }, 1000)    })  }  // 根据user获取一个UserName的Promise  getUserName (user, request_time = 1000) {    return new Promise((resolve, reject) => {      setTimeout(() => {        const child = users.find(item => {          return item.name === user.name        })        resolve(child.name)      }, request_time)    })  }  // 根据userName获取一个Father的Promise  getFatherByChildName (childName) {    return new Promise((resolve, reject) => {      setTimeout(() => {        const father = fathers.find(item => {          return item.child === childName        })        resolve(father)      }, 1000)    })  }  // 抛出一个异常的Promise  throw_Error () {    return new Promise((resolve, reject) => {      setTimeout(() => {        reject(new Error('api.js-------->抛出了一个错误'))      }, 1000)    })  }}

首先 const api = new Api()

  • Promise 的链式顺序模式

    // -----------------------> Promise 的链式顺序模式  function promise_chain () {    api.getUserById(1)      .then(res => {        console.log(res)        return api.getUserName(res)      })      .then(res => {        console.log(res)        return api.getFatherByChildName(res)      })      .then(res => console.log(res))  }  promise_chain()

    每个Promise.then(..)中的返回值(即使返回的不是Promise对象,因为Promise内在机制会将其转换为一个可以使用的Promise)将会作为下一个Promise对象,即Promise.then( return ...)得到的是一个Promise对象,因此可以不断地Promise.then( return ... ).then( return ... ).then( return ... ).then( return ... ).then( return ... ).then()......

  • Promise 的catch

    function promise_lastErro () {    api.throw_Error()    .then(res => console.log('没有错'))    .catch(err => {      console.log(err)      foo.bar()    })    console.log('无法捕捉最后一个catch的错误:foo.bar()')  }  promise_lastErro()
  • Promise 的并发/并行 : Promise.all([...])

    传入的参数是一个Promise的数组
    如果传入的是[],Promise.all([...])将立即决议为完成
    全部Promise完成,Promise.all([...])完成
    如果有一个被拒绝,则Promise.all([...])被拒绝

    function promise_concurrent_1 () {    const p1 = api.getUserById(1,Math.random() * 1000, () => { console.log('p1执行完毕') })    const p2 = api.getUserById(1,Math.random() * 1000, () => { console.log('p2执行完毕') })    Promise.all([p1, p2])      .then(res => console.log('p1 p2 都执行完毕'))  }  promise_concurrent_1()
  • Promise 的任务竞争:竞态(第一优先) : Promise.race([...])

    传入的参数是一个Promise的数组
    如果传入的是[],Promise.race([...])将不会决议,始终处于挂起状态
    只要有一个Primise完成,Promise.race([...])则完成
    如果有一个被拒绝,则Promise.race([...])被拒绝

    function promise_compete () {    const p1 = api.getUserById(1, 2000)    const p2 = api.getUserById(2)    Promise.race([p1, p2]).then(res => console.log(res))  }  promise_compete()
  • 关于Promise.all([...])与Promise.race([...])的变体有很多

    • Promise.none([...]): 要求[...]全部被拒绝,Promise.none([...])决议为完成
    • Promise.any([...]): 与Promise.all([...])类似,但只要求完成一个即可,但是会执行所有Promise
    • Promise.first([...]):与Promise.any([...])类似,但是只要有第一个Promise决议为完成,就不关心后面的Promise
    • Promise.last([...]):与Promise.first([...])相反,最后一个完成的胜出

到此Promise的基本用法就是这些了吧,不知不觉半个小时过去了。

Async/Await

什么是Async/Await

我认为Async/Await是区别于Promise更优雅的体现,它可以简化Promise的大部分代码,让你的代码看上去优雅美观并且大气。并且我支持你,在现在甚至以后,对异步的管理尽可能使用Async/Await。

Async/Await的使用

  • 使用Async/Await代替链式promise(类比 ---> Promise的链式顺序模式)

    async function async_Request () {    console.log('请稍等..此时是三个setTimeOut,每个1s,需要等待3s')    const user = await api.getUserById(1)    const userName = await api.getUserName(user)    const father = await api.getFatherByChildName(userName)    console.log(father)}async_Request()
  • 使用Async/Await的并发与并行

    async function async_Concurrent () {    const users = await api.getUsersByGrade(1)    const usersPromise = users.map(item => api.getUserName(item, Math.random() * 1000))    Promise.all(usersPromise).then(res => {      console.log(res)    })}async_Concurrent()
  • 使用Async/Await的错误捕捉

    async function async_CatchErro () {  try {    await api.throw_Error()    console.log('未捕捉到错误?')  } catch (error) {    console.log(error)  }}async_CatchErro()
  • Async/Await函数的互相调用

    async function async_A () {    const user = await api.getUserById(2)    const userName = await api.getUserName(user)    const father = await api.getFatherByChildName(userName)    return { user, userName, father }}async function async_B () {    console.log('数据获取中...')    const { user, userName, father } = await async_A()    console.log('userInfo',{ user, userName, father })}async_B()
  • Async/Await检索十条数据,串行

    async function async_ten_serial (length = 10) {    try {      const users = []      console.log('串行请求10条数据,每条1秒,请稍等10秒钟....')      while(users.length < 10) {        users.push(await api.getUserById(1))      }      console.log(users)    } catch (error) {      console.log(error)    }}async_ten_serial()
  • Async/Await检索十条数据,并行

    async function async_ten_parallel (length = 10) {    try {      const usersPromise = []      console.log('并行请求10条数据,每条1秒,请稍等1秒钟....')      while(usersPromise.length < 10) {        usersPromise.push(api.getUserById(2))      }      const users = await Promise.all(usersPromise)      console.log(users)    } catch (error) {      console.log(error)    }}async_ten_parallel()

ok!本文并没有讲那些概念性的东西,只是简单地讲这几种实现用代码描述出来,更详细的。请大家参考官方文档,其实对于这篇文章的排版,我发现应该将PromiseAsync/Await对比起来描述,懒得重新排版了,委屈各位手动对比了。(:

(PS: newDate() ---> Sun May 20 2018 00:42:15 GMT+0800 (中国标准时间))
不知不觉竟然写了接近一个小时,溜了溜了,不修仙。

转载地址:http://kybso.baihongyu.com/

你可能感兴趣的文章
使用OpenGrok搭建 可搜索可跳转的源码 阅读网站
查看>>
HTML5开发中的javascript闭包
查看>>
Android ContentProvider调用报错"Bad call:..."及相关Binder权限问题分析
查看>>
ionic3 教程(二)登录页制作
查看>>
Python正则表达式初识(四)
查看>>
不务正业的前端之SSO(单点登录)实践
查看>>
配置通过VLANIF实现跨设备VLAN内通信
查看>>
一站式计费解决方案——腾讯计费首次亮相昆明
查看>>
Linux-正则表达式
查看>>
文字转语音转换的方法有哪些?
查看>>
基本shell脚本的编辑及变量
查看>>
免密码登陆
查看>>
加密和解密 tar
查看>>
我的友情链接
查看>>
[李景山php]每天TP5-20161216|thinkphp5-helper.php-1
查看>>
VMware、Workstation 使用
查看>>
Windows Server 2012正式版RDS系列⑽
查看>>
The MySQL server has gone away
查看>>
Hibernate导出表代码
查看>>
用户输入和while循环
查看>>