前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《你不知道的JavaScript》:ES6 Promise API 详解

《你不知道的JavaScript》:ES6 Promise API 详解

作者头像
前端_AWhile
发布2019-08-29 11:12:44
6570
发布2019-08-29 11:12:44
举报
文章被收录于专栏:前端一会前端一会

本篇系统总结ES6 Promise API。

new Promise(…)

先看下 new Promise(…) 构造器。

new Promise(…) 构造器的参数必须提供一个函数回调。这个回调是同步的或者立即调用的。这个函数又接受两个函数回调参数,用以支持promise的决议。通常把这两个函数回调参数称为 resolve()reject()

代码语言:javascript
复制
var p = new Promise( function(resolve, reject){
    // resolve() 用于决议/完成这个promise
    // reject() 用于拒绝这个 promise
} )

reject()就是拒绝这个promise。但是resolve()既可能完成promise,也可能拒绝,要根据传入参数而定。如果传给resolve()的是一个非Promise、非thenable的立即值,这个promise就会用这个值完成。 但是如果传给resolve()的是一个真正的Promise或thenable值,这个值就会被递归展开,并且(要构造的)promise将取用其最终决议值或状态。

代码语言:javascript
复制
var p1 = function(num){
    return new Promise(function (resolve, reject) {
        if(num > 10){
            resolve(num);
        }else {
            reject("num 小于等于10");
        }
    })
}

function res() {
    return new Promise(function (resolve, reject) {
        //传入的是Promise值,此时resolve()递归传递出去的值要依据传入的promise值而定,是完成还是拒绝状态,并且(要构造的)promise将取用其最终决议值或状态
        resolve(p1(12));        // 完成状态
        // resolve(p1(6));      // 拒绝状态
    })
}
res()
.then(function (val) {
    console.log(val);
})
.catch(function (err) {
    console.log(err);
})

resolve()和reject()

下面看下resolve()和reject()。

创建一个已被拒绝的Promise的快捷方式是使用Promise.reject(),所以以下两个promise是等价的:

代码语言:javascript
复制
var p1 = new Promise(function(resolve, reject){
    reject("Oops!")
})

var p2 = Promise.reject("Oops!")

Promise.resolve() 常用于创建一个已完成的Promise,使用方式与Promise.reject()类似。但是Promise.resolve()也会展开thenable值。在这种情况下,返回的Promise采用传入的这个thenable的最终决议值,可能是完成,也可能是拒绝。

代码语言:javascript
复制
var fulfilledTh = {
    then: function(cb){ cb(42) }
}
var rejectedTh = {
    then: function(cb, errCb){
        errCb("Oops")
    }
}
var p1 = Promise.resolve(fulfilledTh);
var p2 = Promise.resolve(rejectedTh);

// p1是完成的promise
// p2是拒绝的promise

此外,如果传入的是真正的Promise,Promise.resolve()什么都不会做,只会直接把这个值返回。所以对不了解属性的值调用Promise.resolve(),如果它恰好是一个真正的Promise,是不会有额外开销的。

代码语言:javascript
复制
// p1(..)的返回值是一个真正的Promise
var p1 = function(num){
    return new Promise(function (resolve, reject) {
        if(num > 10){
            resolve(num)
        }else {
            reject("num 小于等于10")
        }
    })
}
var res = Promise.resolve(p1(12));
res
.then(function(val){
    console.log(val);
})
.catch(function (err) {
    console.log(err);
})

then()和catch()

每个Promise实例都有then()和catch()方法,通过这两个方法可以为这个Promise注册完成和拒绝处理函数。当Promise决议之后,会立即调用这两个处理函数之一,但不会两个都调用,而且总是异步调用

then()接受一个两个参数:第一个用于完成回调,第二个用于拒绝回调。如果两者中的任何一个被省略或者作为非函数值传入的话,就会替换为相应的默认回调。默认完成回调只是把消息传递下去,而默认拒绝回调则只是重新抛出(传播)其接收到的出错原因。

catch()只接受一个拒绝回调作为参数,并自动替换默认完成回调。也就是说,其等价于then(null, rejected):

代码语言:javascript
复制
p.then(fulfilled);
p.then(fulfilled, rejected);
p.cathc(rejected);      // 或者 p.then(null, rejected);

then()catch()也会创建并返回一个新的promise,这个promise可以用于实现Promise链式流程控制。如果完成或拒绝回调中抛出异常,返回的promise是被拒绝的。如果任意一个回调返回非Promise、非thenable的立即值,这个值就会被用作返回promise的完成值。如果完成处理函数返回一个promise或者thenable,那么这个值就会被展开,并作用返回promise的决议值。

Promise.all([…]) 和 Promise.race([…])

ES6 Promise API有两个静态辅助函数:Promise.all([...])Promise.race([...])。它们都会创建一个Promise作为它们的返回值。这个promise的决议完全由传入的promise数组控制。

Promise.all([...])来说,只有传入的所有promise都完成,返回promise才能完成。如果有任何promise被拒绝,返回的主promise就会立即被拒绝(并且会抛弃任何其他promise的结果)。如果完成的话,就会得到一个数组,其中包含传入的所有promise的完成值。对于拒绝的情况,你只会得到第一个拒绝promise的拒绝理由值。这种模式传统上被称为门,即所有人都到齐了才开门。

对于Promise.race([...])来说,只有第一个决议的promise(完成或拒绝)取胜,并且其决议结果成为返回promise的决议。这种模式传统上称为门闩,即第一个到达者打开门闩通过。

代码语言:javascript
复制
var p1 = Promise.resolve(42);
var p2 = Promise.resolve("Hello World");
var p3 = Promise.reject("Oops");

//如果有任何promise被拒绝,返回的主promise就会立即被拒绝(并且会抛弃任何其他promise的结果),你只会得到第一个拒绝promise的拒绝理由值
Promise.all([p1, p2, p3])
.then(function(val){
    console.log(val);
})
.catch(function(err){
    console.log(err);   // Oops
})

// 第一个决议的promise(完成或拒绝)取胜,并且其决议结果成为返回promise的决议
Promise.race([p1, p2, p3])
.then(function(val){
    console.log(val);   // 42
})
.catch(function(err){
    console.log(err);   
})

// 如果完成的话,就会得到一个数组,其中包含传入的所有promise的完成值
Promise.all([p1, p2])
.then(function(val){
    console.log(val);   // [42, Hello World]
})
.catch(function(err){
    console.log(err);   
})

注意,如果向Promise.all([...])中传入空数组,它会立即完成,但Promise.race([...])会挂住,且永远不会决议。

代码语言:javascript
复制
// 向`Promise.all([...])`中传入空数组,它会立即完成
Promise.all([])
.then(function(val){
    console.log(val);   // []
})
.catch(function(err){
    console.log(err);
})

// 向`Promise.race([...])`中传入空数组,它会挂住,且永远不会决议
Promise.race([])
.then(function(val){
    console.log(val);   // 不进决议
})
.catch(function(err){
    console.log(err);   // 不进拒绝
})

以上就是ES6 Promise API,它们非常直观也很用,对于异步的支持很友好,可以用来重构回调地狱代码,使代码更易于追踪和维护。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-01-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端小二 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • new Promise(…)
  • resolve()和reject()
  • then()和catch()
  • Promise.all([…]) 和 Promise.race([…])
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档