Promise深入探索

栏目: JavaScript · 发布时间: 5年前

内容简介:假设我们要调用一个工具 foo(..) ,且并不确定得到的返回值是否是一个可信任的行为良好的 Promise,但我们可以知道它至少是一个 thenable。Promise.resolve(..) 提供了可信任的 Promise 封装工具对于用 Promise.resolve(..) 为所有函数的返回值(不管是不是 thenable)都封装一层。另一个好处是,这样做很容易把函数调用规范为定义良好的异步任务。如果 foo(42) 有时会返回一个立即值,有时会返回 Promise,那么 Promise.reso
  1. 如果向Promise.resolve()传递一个非promise非thenalbe的立即值,就会得到一个用这个值填充的promise。
  2. 如果向Promise.resolve()传递一个promise,就只会返回同一个promise
  3. 如果向Promise.resolve()传递了一个非Promise的thenable值,前者会试图展开这个值,而且展开过程中会持续到提取出一个具体的非类Promise的最终值。

假设我们要调用一个工具 foo(..) ,且并不确定得到的返回值是否是一个可信任的行为良好的 Promise,但我们可以知道它至少是一个 thenable。Promise.resolve(..) 提供了可信任的 Promise 封装工具

// 不要只是这么做:
foo( 42 )
.then( function(v){
    console.log( v );
} );

// 而要这么做:
Promise.resolve( foo( 42 ) )
.then( function(v){
    console.log( v );
} );
复制代码

对于用 Promise.resolve(..) 为所有函数的返回值(不管是不是 thenable)都封装一层。另一个好处是,这样做很容易把函数调用规范为定义良好的异步任务。如果 foo(42) 有时会返回一个立即值,有时会返回 Promise,那么 Promise.resolve( foo(42) ) 就能够保证总会返回一个 Promise 结果

默认错误处理函数

如果一个promise链中的上一级promise抛出一个错误,但是下一级promise并没有配置错误处理函数,promise会有一个默认处理函数来处理这个错误,即吧这个错误重新抛出给下一级promise的错误处理函数。

如果一直找到最后一级的promise都没有错误处理函数,那么promise会在控制台打出一个错误信息,并且这个错误是有可能中断nodejs进程的。

DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
复制代码

(在浏览器环境貌似并不会中断进程)

Promise链

  • 调用promise的then方法,会自创建一个新的Promise,并且决议的值就是then中resolve/reject函数的返回值;
  • 如果resolve/reject函数返回的是一个Promise,那么会等待这个Promise的决议结果,并将决议结果作为当前then方法生成的Promise的决议值;
var a = new Promise(function(resolve, reject) {
  resolve(10)
}).then(
  res => {
    return b
  }
).then(res => {
  console.log('1err:' + res)
  return res
}).then(res => {
  console.log('1res:' + res)
  return res
}, err => {
  console.log('2err:' + err)
})

var b = new Promise(function(resolve, reject) {
  resolve(123123123123)
})
复制代码

Promise构造器中两个回调函数

reject很好理解就是处理错误,那么resolve为什么不用fulfill呢?貌似应该是处理成功请求?实际上resolve的意思是决议,也就是可能是成功的结果也可能是失败的结果;比如所给resolve传入thenable或者一个真正的Promise,这个时候决议的结果取决于返回值的决议结果,所以说resolve返回的有可能是成功也有可能是失败;

var rejectedPr = new Promise( function(resolve,reject){
    // 用一个被拒绝的promise完成这个promise
    resolve( Promise.reject( "Oops" ) );
} );

rejectedPr.then(
    function fulfilled(){
        // 永远不会到达这里
    },
    function rejected(err){
        console.log( err ); // "Oops"
    }
);
复制代码

前面提到的 reject(..) 不会像 resolve(..) 一样进行展开。如果向 reject(..) 传入一个 Promise/thenable 值,它会把这个值原封不动地设置为拒绝理由。后续的拒绝处理函数接收到的是你实际传给 reject(..) 的那个 Promise/thenable,而不是其底层的立即值。

回调函数简介

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应

而then方法的两个回调函数应该使用onFulfilles/fulfilled和onRejected/rejected因为对于then来说第一个回调只能处理正确的结果。

(fulfilled the promis 兑现承诺)

Promise错误处理函数的细节

通常我们有两种写法来捕获错误:

var a = new promise(function(resolve, reject){})

// 在then方法的内部第二个回调捕获
a.then(res => {
    
}, err => {
    
})

// 在catch方法中捕获
a.then(res => {}).catch(err => {})

复制代码

那么这两种方法有什么不同? 实际上第二种方法是包含第一种方法的,只不过then方法中的第二个回调被默认执行了,而默认的错误处理回调只是简单的抛出错误,然后就会被catch方法捕获; 这里就有一个问题,如果a的决议是resolve,那么就会调用then的第一个成功回调,如果这个成功回调中的具体代码中发生了错误,第一种方法是无法捕获的,而第二种方法是可以捕获的。

var a = new promise(function(resolve, reject){
    resolve(12)
})

// 在then方法的内部第二个回调捕获
a.then(res => {
    aaa() // 这里aaa是不存在的会发生错误
}, err => {
    console.log(err) // 不会走这里,所以错误不会被捕获
})

// 在catch方法中捕获
a.then(res => {
    aaa() // 这里aaa是不存在的会发生错误
}).catch(err => {
    console.log(err) // 这里会捕获then方法中的所有错误,自然也能捕获aaa导致的错误
})
复制代码

Promise.race()的应用场景

实际上Promise.race([p1, p1, p3])这种模式在程序设计中通常是一种被称为竞态的bug,但是它还是有一定的应用场景:

  1. 请求超时处理
var p1 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve(2222)
  }, 2000)
})
// 定义一个超时函数,如果p1超过这个时间还未决议,就认为这个请求超时了。
var timeoutPromise = new Promise(function(resolve, reject) {
  setTimeout(function() {
    reject('timeout')
  }, 1000)
})

Promise.race([p1, timeoutPromise]).then(res => {
  console.log(res)
}).catch(err => {
  console.log(err)
})
复制代码

有时候我们可能会想,Promsie.race()中那些别丢弃(比赛中失败)的Promise哪里去了?当然最后会被垃圾回收,但是,Promsie不能别停止,它们依旧会完成自己的任务直到决议,目前来看只是被默默的丢弃了,像空气一样,或许在以后的规范中会添加类似与finally之类的回调函数用于处理这些被遗弃的孩子。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java常用算法手册

Java常用算法手册

2012-5 / 59.00元

《Java常用算法手册》分三篇,共13章,分别介绍了算法基础、算法应用和算法面试题。首先介绍了算法概述,然后重点分析了数据结构和基本算法思想;接着,详细讲解了算法在排序、查找、数学计算、数论、历史趣题、游戏、密码学等领域中的应用;最后,列举了算法的一些常见面试题。书中知识点覆盖全面,结构安排紧凑,讲解详细,实例丰富。全书对每一个知识点都给出了相应的算法及应用实例,虽然这些例子都是以Java语言来编......一起来看看 《Java常用算法手册》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具