资讯专栏INFORMATION COLUMN

半理解系列--Promise的进化史

Eminjannn / 3372人阅读

摘要:异步编程一般用来调取接口拉数据。通过我描述的篇幅,就知道异步编程比同步编程麻烦许多。远古时期,异步编程是通过回调函数来解决的。

半理解系列--Promise的进化史

学过js的都知道,程序有同步编程和异步编程之分,同步就好比流水线,一步一个脚印,做完上个任务才做下一个,异步编程好比客服,客服接了一个电话,收到了一个任务,然后把任务交给另外的人来处理,同时,继续接听下一个电话,等到另外的人处理完任务了,再通知客服,客服再反馈给第一个打电话的人。异步编程一般用来调取接口拉数据。

通过我描述的篇幅,就知道异步编程比同步编程麻烦许多。远古时期,异步编程是通过回调函数来解决的。但是回调函数会有回调地狱的问题,回调的多了,维护人员看起来头都大了,好比:taskC需要等待taskB做完(taskC才执行),taskB又需要等待taskA做完(taskB才执行)

function taskA (cb) {
  //..do task A
  cb()
}
function taskB(cb){
  //..do task B
  cb()
}
function taskC(cb){
  //..do task C
  cb()
}
taskA(function(){
  taskB(function(){
    taskC()
  })
})
...以此类推,不断循环嵌套,最终陷入地狱

而Promise就把这一系列的回调,通过链式调用的方式连接起来,看起来清爽多了。同样是上面的代码,Promise可以这么写(伪代码)

new Promise().then(taskA).then(taskB).then(taskC)
promise的使用
const promise = new Promise((resolve,reject)=>{
  if (/*do something done*/){
    resolve() // 可在此传参数
  } else {
    // do something fail
    reject() // 可在此传参数
  }
})
promise.then(()=>{
  //do something
}).catch(e => { throw e})

上面的resolve,可以当作task函数的cb回调函数,当resolve()执行的时候,then方法中的回调会被执行,如果是reject执行,错误会被catch捕捉。

Promise的静态方法

上面说的thencatch都是Promise的原型方法,即Promise.prototype.then/catch
Promise本身有两个静态方法,其作用类似 new Promise()

Promise.resolve()

const promise1 = Promise.resolve()

等价于

const promise2 = new Promise((reslove)=>{
  reslove()
})

使用该方法调用then方法
Promise.reject()

const promise1 = Promise.reject()

等价于

const promise2 = new Promise((resolve,reject)=>{
  reject()
})

使用该方法会被catch捕捉

Promise的链式调用

Promise的实例对象的then方法是可以重复调用的,then方法返回的是一个promise实例对象,所以可以重复调用then方法,并且(敲黑板),上一个then方法的返回值,会作为下一个then方法的参数传递

举个栗子:

const promise = Promise.resolve("start")

promise.then((params)=>{
  console.log(params) // start
  return "aa"
}).then((params) => {
  console.log(params) // aa
  return "bb"
}).then((params)=>{
  console.log(params) // bb
  return "cc"
})

// 最后会返回一个状态是resolve(cc)的promise对象:Promise {: "cc"}

深入一下(又不会怀孕)

function badAsyncCall() {
  var promise = Promise.resolve();
  promise.then(function() {
      // 任意处理
      return "newVar";
  });
  return promise;
}
// 修改一下
function goodAsyncCall() {
  var promise = Promise.resolve();
  return promise.then(function() {
      // 任意处理
      return "newWar";
  });
}

以上两个写法是不是很相似,唯一不同的就是return的处理。但调用,badAsynccall会出错,而anAsyncCall能正确执行,比如:

badAsyncCall().then(params => { console.log("bad--",params)}) // bad-- undefined
goodAsyncCall().then(params => { console.log("good--",params)}) // good-- newWar

分析:第一种,错误写法,首先在 promise.then 中产生的异常不会被外部捕获,此外,也不能得到 then 的返回值,即使其有返回值。
原因:由于每次 promise.then 调用都会返回一个新创建的promise对象,第一种返回的promise,相当于没有调用过函数内部的then方法,是一个全新的promise实例对象
结论: 统一使用promise链式调用,如:promise.then(taskA).then(taskB)

### async&await和promise的前世缘缘

promise说白了还是用回调的方式来解决异步问题,跟真正同步还是有差距的。
异步编程的最高境界,就是根本不用关心它是不是异步!(来之ruanyifeng老师的话)

所以,async&await方案出现了

用法:

function readFile(fileName) {
  return new Promise((resolve,reject)=>{
    fs.readFile(fileName, function(error, data) {
      if (error) return reject(error);
      resolve(data); // 向thenc传送异步读取文件的数据
    });
  })
}

// 调用

readFile(fileName).then(function(data){
  console.log("prmoise read files data --", data)
})


// 等价于

async function asyncFn(fileName){
  const data = await readFile(fileName)
  console.log("await data --", data)
  return data
}

asyncFn(fileName) 

写法是不是简洁了许多!
其实async就是一个Promise的语法糖,它的返回值是一个promise对象,因此可以用then方法做链式调用(但参数就是async函数中的返回值,如上文的data!!)

async函数中还可以不使用promise,比如:

async function asyncFn(){
  const data = await setTimeout(function(){
    console.log("setTimeout") 
    return "data"
  },1000)
  console.log("data",data) // Timeout {} 对象
}
console.log("async",asyncFn()) // Promise {  }

但这两者,其实经常混用,常见的就是readFile函数的做法啦

看懂以上的,才大家出一道题看看能不能懂;

async function asynFn(){ 
  await Promise.resolve("aaa")
  const data = {
    b:"bb",
    c:function(){ return this.b }
  }
  return data  //return 作为参数传递给then then的chain链也是通过return参数来不断传递给后面的then
}
var cball = asynFn()
cball.then(function(data){
  console.log("data:",data)
})

还有一种异步编程的语法糖: * & yield
跟async基本一样,不在本文讨论的重点。有兴趣自行google啦

参考资料:
async 函数的含义和用法
Promise 对象

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107430.html

相关文章

  • JavaScript 异步化史

    摘要:签订协议的两方分别是异步接口和。在异步函数中,使用异常捕获的方案,代替了的异常捕获的方案。需要注意的是,在异步函数中使异步函数用时要使用,不然异步函会被同步执行。 同步与异步 通常,代码是由上往下依次执行的。如果有多个任务,就必需排队,前一个任务完成,后一个任务才会执行。这种执行模式称之为: 同步(synchronous) 。新手容易把计算机用语中的同步,和日常用语中的同步弄混淆。如,...

    luzhuqun 评论0 收藏0
  • 前端文档收集

    摘要:系列种优化页面加载速度的方法随笔分类中个最重要的技术点常用整理网页性能管理详解离线缓存简介系列编写高性能有趣的原生数组函数数据访问性能优化方案实现的大排序算法一怪对象常用方法函数收集数组的操作面向对象和原型继承中关键词的优雅解释浅谈系列 H5系列 10种优化页面加载速度的方法 随笔分类 - HTML5 HTML5中40个最重要的技术点 常用meta整理 网页性能管理详解 HTML5 ...

    jsbintask 评论0 收藏0
  • 前端文档收集

    摘要:系列种优化页面加载速度的方法随笔分类中个最重要的技术点常用整理网页性能管理详解离线缓存简介系列编写高性能有趣的原生数组函数数据访问性能优化方案实现的大排序算法一怪对象常用方法函数收集数组的操作面向对象和原型继承中关键词的优雅解释浅谈系列 H5系列 10种优化页面加载速度的方法 随笔分类 - HTML5 HTML5中40个最重要的技术点 常用meta整理 网页性能管理详解 HTML5 ...

    muddyway 评论0 收藏0
  • 人工智能革命:从ANI到AGI道路

    摘要:截至目前,人类大脑是已知宇宙中最复杂的物体。但是天河二号也是一个庞大的家伙,它占地平方米,使用兆瓦的电力大脑只需瓦,耗资亿美元建造。建议,通过查看可以以,美元购买多少来考虑计算机的状态。 showImg(http://upload-images.jianshu.io/upload_images/13825820-c158f685feaf8ae6.jpg?imageMogr2/auto-...

    pkwenda 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<