资讯专栏INFORMATION COLUMN

通过回调来理解Promise

DevYK / 2279人阅读

摘要:可信任性确定性在解决上述的回调函数的问题之前,有必要先来认识一下的一些主要方法的起点执行结果依次是,,,代码解读以上代码体现了的如下特性一旦决议调用过一次或者就不再重复调用决议回调或者改变决议回调。

通过回调来理解Promise

我们都知道Promise的出现是为了规避回调地狱的,由此,我们先来深入了解一下回调的缺陷:

回调

1、缺乏信任

2、不确定性

Example

var money = 30;
order(money,function getOrder(orderId){  // order是一个第三方的下订单的回调函数
   orderId && pay(orderId);  // 获取订单编号之后调用第三方支付pay方法去付款 
})
// ...同步代码

代码解读:上面的代码只是常规代码中的一部分,其中order是一个第三方下订单的方法,需要携带回调函数过去获取订单编号,这里面就存在一些信任性和不确定性的问题,如:

1、有可能回调函数getOrder始终不会被调用,那我们就永远拿不到订单编号去支付;
2、有可能回调了,可是回调了不止一次,导致我们重复去支付了;
3、不确定回掉时间,有可能立马回调,那么接下来的同步代码就会在回调之后执行,有可能它内部调用了异步代码再回调,那么接下来的同步代码就会在回调之前执行。
4、也有可能下订单的第三方模块自己内部出错了,导致我们没办法捕获异常;

上面只是回调的一部分缺陷,但其实当我们不喜欢一个东西的时候总有这么多理由,当我们喜欢一个东西的时候,没有理由也会找一堆理由的,下面就是Promise的理由。

Promise

1、可信任性
2、确定性

在解决上述的回调函数的问题之前,有必要先来认识一下Promise的一些主要方法:

1、Promise的起点new Promise()

Example

console.log(1);
let promise = new Promise(function PromiseBack(resolve,reject){
    resolve();
    resolve();
    reject();
    reject();
    console.log(2);
}).then(()=>{
    console.log(4);
},()=>{
    console.log(5);
})
console.log(3);
// 执行结果依次是:1,2,3,4

代码解读:以上代码体现了new Promise的如下特性:

1、一旦决议(调用过一次resolve或者reject)就不再重复调用决议回调或者改变决议回调。

2、决议代码是同步的,可是决议的成功或失败的回调代码一定是异步的,而且Promise的异步实现比setTimeout的调用时间更早,因为回调决议存在于Event loop的microtask队列中。

2、多Promise同时执行:Promise.all([ .. ])

Example

let promise1 = new Promise(function(resolve,reject){
    resolve(1);
});
let promise2 = new Promise(function(resolve,reject){
    resolve(2);
    // reject(3);
});
let promise3 = Promise.all([promise1,promise2]).then(function resolveBack(result){
    console.log(result);    // 打印结果是:[ 1, 2 ]
},function rejectBack(result){
    console.log(result);    // 当promise2注释部分放开,非注释部分注释,打印结果是:3
})

代码解读:Promise.all方法对于promise数组的决议是:当其中所有的promise都是成功决议的时候,就会调用成功的决议回调resolveBack,并且把promise数组的决议值以数组的形式按照顺序返回resolve中的值;如果其中哪怕有一个失败的决议都会调用失败的决议回调rejectBack,并且只返回promise宿主中失败的决议值,以数组顺序返回

3、多Promise竞赛执行:Promise.race([ .. ])

Example

let promise1 = new Promise(function(resolve,reject){
  setTimeout(function(){
    resolve(1);
  },100);
});
let promise2 = new Promise(function(resolve,reject){
  setTimeout(function(){
   //resolve(2);
    reject(3);
  },50);
});
let promise3 = Promise.race([promise1,promise2]).then(function resolveBack(result){
    console.log(result);    // 打印结果是:2
},function rejectBack(result){
    console.log(result);    // 当promise2注释部分放开,非注释部分注释,打印结果是:3
})

代码解读:Promise.race方法和all方法不同,它对于promise数组的决议是:当promise数组中有一个成功了,那就会立即执行成功的决议回调,当有一个失败了,就会立即执行失败的决议回调,所以,它也叫竞赛决议,它的一个常用的应用场景就是异步请求超时处理,代码如下:
Example:

// request(..)是一个支持Promise的Ajax工具
let promise1 = request( "http://some.url.1/");
let promise2 = function(second=1000){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      reject("请求超时");
    },second)
  })
};
let promise3 = Promise.race([promise1,promise2(3000)])
.then(function resolveBack(result){
    console.log(result);
},function rejectBack(result){
    console.log(result);    // 当请求超时3秒钟就决议失败,打印错误信息,如果这里信息是统一处理,那最好超时的值构造成和异步请求返回错误结果的值一致
})
4、Promise错误处理catch...

Example

new Promise((resolve,reject)=>{
  console.log(a);
}).catch((err)=>{
  console.log(err);     // 打印结果:33 [ReferenceError: a is not defined]
})

代码解读:catch和then一样都是Promise的实例方法,而且也都调用完成之后也都会返回一个新的Promise实例,这样就可以继续then或catch了,这也就是Promise的“链式流”。其实catch本身实现和then是类似的,可以完全看成是then仅有失败决议回调,即:then(null,(err)=>{})。也就是说then的失败决议当Promise决议代码出错了,哪怕没有调用reject方法,也是会被捕获到错误的

总结

浏览过上述方法之后,我们现在来解决一开始我们遇到的那个回调函数的问题,解决问题代码如下:

Example

var money = 30;
let promise1 = new Promise(function(resolve,reject){
    order(money,function getOrder(orderId){ 
        orderId ? resolve(orderId) : reject(orderId);
    }); 
});
let promise2 = function(second=1000){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      reject("请求超时");
    },second)
  })
};
let promise3 = Promise.race([promise1,promise2(3000)])
.then(function resolveBack(result){
    console.log(result);
},function rejectBack(result){
    console.log(result);    // 当请求超时,或者order内部代码错误等都会调用失败的决议
})
// ...同步代码

代码解读:上面这个Promise例子展示了对回调问题的规避,具体解决思路是:

1、通过使用Promise.race竞赛决议方法解决如果第三方的order方法不调用getOrder的情况,可以定位到具体的错误代码和错误原因;
2、根据Promise的决议特性:一旦决议不可状态不可更改,不可重复。解决了回调了不止一次的问题;
3、根据Promise的决议回调是异步的特性,决议的回调一定是异步的特性,解决了回调时间的不确定性。
4、根据rejectBack类似catch的特性,失败的决议回调是可以捕获到决议代码异常的报错的,那这样,如果第三方内部出现了问题,是可以捕获到的。

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

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

相关文章

  • [译] 深入理解 Promise 五部曲:2. 控制权转换问题

    摘要:直到最近,我们仍然在用简单的回调函数来处理异步的问题。当我们只有一个异步任务的时候使用回调函数看起来还不会有什么问题。 原文地址:http://blog.getify.com/promis... 厦门旅行归来,继续理解Promise 在上一篇深入理解Promise五部曲:1.异步问题中,我们揭示了JS的异步事件轮询并发模型并且解释了多任务是如何相互穿插使得它们看起来像是同时运行的。...

    alanoddsoff 评论0 收藏0
  • ES6-7

    摘要:的翻译文档由的维护很多人说,阮老师已经有一本关于的书了入门,觉得看看这本书就足够了。前端的异步解决方案之和异步编程模式在前端开发过程中,显得越来越重要。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。 JavaScript Promise 迷你书(中文版) 超详细介绍promise的gitbook,看完再不会promise...... 本书的目的是以目前还在制定中的ECMASc...

    mudiyouyou 评论0 收藏0
  • 【译】理解回调Promise

    摘要:理解回调和原文自工程师博客,传送门这两个概念是编程语言的基本内容。回调地狱就是滥用回调。通常,在回调中,错误作为第一个参数传递。这个具有这两个函数作为参数的回调称为执行程序。到目前为止,我希望我已经让自己了解了回调和。 理解回调和Promise 原文自工程师Fernando Hernandez博客,传送门 这两个概念是Javascript编程语言的基本内容。因为这种语言是在异步编程的...

    liuyix 评论0 收藏0
  • 从源码看 Promise 概念与实现

    摘要:从源码看概念与实现是异步编程中的重要概念,它较好地解决了异步任务中回调嵌套的问题。这些概念中有趣的地方在于,标识状态的变量如都是形容词,用于传入数据的接口如与都是动词,而用于传入回调函数的接口如及则在语义上用于修饰动词的副词。 从源码看 Promise 概念与实现 Promise 是 JS 异步编程中的重要概念,它较好地解决了异步任务中回调嵌套的问题。在没有引入新的语言机制的前提下,这...

    kel 评论0 收藏0
  • JavaScript 异步

    摘要:从最开始的到封装后的都在试图解决异步编程过程中的问题。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。写一个符合规范并可配合使用的写一个符合规范并可配合使用的理解的工作原理采用回调函数来处理异步编程。 JavaScript怎么使用循环代替(异步)递归 问题描述 在开发过程中,遇到一个需求:在系统初始化时通过http获取一个第三方服务器端的列表,第三方服务器提供了一个接口,可通过...

    tuniutech 评论0 收藏0

发表评论

0条评论

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