资讯专栏INFORMATION COLUMN

ES6 Promise

mengbo / 813人阅读

摘要:可以捕获返回值返回一个,处理状态变为的情况参数是一个函数,有一个参数,用来记录变成状态返回的原因。示例用于将现有对象转为对象等价于返回值返回一个对象,这个对象是被给定的值解析过的。

参考
https://pouchdb.com/2015/05/1...
https://developer.mozilla.org...
http://es6.ruanyifeng.com/#do...

Promises
是一种编写异步代码的方法。
Promise 对象
用于表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值。
Promise 使用
Promise适用于这样的场景,后面的操作必须根据前面的操作的结果做出相应的反应。 那么后面的操作必须等前面的操作完成并且获得前面操作的结果。

假设我们现在有三个操作doSomethingFirst,doSomethingSecond 和finalHandler。
doSomethingSecond 需要根据 doSomethingFirst 的结果做出反应
finalHandler 需要根据 doSomethingSecond 的结果做出反应
流程如下:

//resOfDoSomethingFirst 是 DoSomethingFirst的结果
  doSomethingFirst
|-----------------|
                  doSomethingSecond(resOfDoSomethingFirst)
                  |------------------|
                                     finalHandler(doSomethingSecond的结果)
                                     |------------------|
实现这个场景需要解决以下两个问题:
    后面的操作 如何知道 前面的操作 完成了
    后面的操作 如何知道 前面的操作 的执行结果是什么

//包装第一个操作在 doSomethingFirst 中
const doSomethingFirst = new Promise(function(resolve, reject) {
  // ... some code

  if (/*操作成功 */){
    resolve(doSomethingFirstValue);     //将doSomethingFirst对象的状态从“pending”变为“resolved”
  } else {
    reject(doSomethingFirstError);
  }
});

//包装第二个操作在 
doSdoSomethingSecond(resOfDoSomethingFirst) {
      // ... some code
    return somePromise(); //返回一个promise 对象
});

//整个操作流程如下:
doSomethingFirst()
    .then(doSdoSomethingSecond)
    .then(finalHandler)
    .catch(function (err) {
      console.log(err);
    })
    .finally(() => {···});
    
通过new Promise创建的Promise 实例doSomethingFirst 有以下方法:
    Promise.all(iterable)
    Promise.race(iterable)
    Promise.reject(reason)
    Promise.resolve(value)
    Promise.prototype.catch(onRejected)
    Promise.prototype.then(onFulfilled, onRejected)
    Promise.prototype.finally(onFinally)

1. doSomethingSecond 如何知道 doSomethingFirst 操作完成了
    通过doSomethingFirst状态的变更通知。

    一个 Promise有以下几种状态:
        pending: 操作未完成。
        fulfilled: 操作完成,并且成功。
        rejected: 操作完成,但是失败。

    resolve()函数:
        在异步操作成功时调用
        作用是:将Promise对象的状态从 pending 变为 fulfilled,并将异步操作的结果,作为参数传递出去;
    reject()函数:
        在异步操作失败时调用
        作用是:将Promise对象的状态从 pending 变为 rejected, 并将异步操作的错误,作为参数传递出去。

    当操作完成时(Promise对象的状态变为fulfilled 或 rejected时),doSomethingFirst 就会通过then()函数调用doSomethingSecond,doSomethingSecond就知道doSomethingFirst已经完成了。
2. doSomethingSecond 如何知道 doSomethingFirst 的执行结果是什么
    doSomethingFirst通过给then()函数调用doSomethingSecond(resOfDoSomethingFirst)并把执行结果resOfDoSomethingFirst作为参数传递给doSomethingSecond

Promise.prototype.then(onFulfilled, onRejected)
用于为 Promise 实例添加状态改变时的回调函数
返回值:一个新的 Promise,所可以采用链式写法,then()函数后面再调用then()函数
参数:
    onFulfilled 
        是一个函数,有一个参数,用来记录变成fulfilled状态返回的结果
        当doSomethingFirst这个Promise的状态变成fulfilled 时,onFulfilled作为回调函数被调用
    onRejected
        是一个函数,有一个参数,用来记录变成rejected状态返回的原因
        当doSomethingFirst这个Promise的状态变成rejected 时,onRejected作为回调函数被调用

    在当前的例子里参数onFulfilled就是doSomethingSecond(resOfDoSomethingFirst),resOfDoSomethingFirst 记录了doSomethingFirst 变成fulfilled状态返回的结果。

注意事项:
    当给then()传入的参数不是函数时,它实际上将其解释为then(null),将使先前的Promise的结果落空
        Promise.resolve("foo").then(Promise.resolve("bar")).then(function (result) {
          console.log(result); // foo
        });    
            等价于
        Promise.resolve("foo").then(null).then(function (result) {
            console.log(result);// foo 
        });
    
        上面的代码并没有按照我们期望的打印"bar", 而是打印"foo"
        正确的写法是:
        Promise.resolve("foo").then(function () {
          return Promise.resolve("bar");
        }).then(function (result) {
          console.log(result); // bar
        });


给then()传入的参数是函数时,函数的内部我们可以做以下三件事:
    1. 返回另外一个promise
    2. 返回一个同步值
    3. 抛出一个同步错误

    示例:返回另外一个promise
        doSomethingFirst()
            .then(doSdoSomethingSecond)
            .then(finalHandler)
    
        //somePromise() 返回promise对象
        function doSomethingSecond(resOfDoSomethingFirst) {
            return somePromise(); //有return, finalHandler接受到的是resOfDoSomethingSecond
            //somePromise();// 没有return, finalHandler接受到的是undefined
        }
        function finalHandler(resOfDoSomethingSecond) {
            // handle resOfDoSomethingSecond
        }

    示例:返回同步值 && 抛出一个同步错误
        返回同步值实际上是将同步代码转换为Promisey代码的一种很棒的方法。例如,假设我们有一个用户的内存缓存。我们可以做到:
        
            //getUserByName  和 getUserAccountById 都返回promise对象
            getUserByName("nolan").then(function (user) {
              if (user.isLoggedOut()) { //如果用户注销
                throw new Error("user logged out!"); // 抛出一个同步错误
              }
              if (inMemoryCache[user.id]) {
                return inMemoryCache[user.id];       //  返回一个同步值!
              }
              return getUserAccountById(user.id);    // 返回一个promise!
            }).then(function (userAccount) {
              // I got a user account!
            }).catch(function (err) {
              // Boo, I got an error!
            });
            
        如果用户注销,catch()将收到一个同步错误;通过callbacks,这个错误会被忽略
        如果任何promise被拒绝,catch()将收到一个异步错误。

通常情况下,一个promise 依赖于另一个promise ,但当我们需要两个promises的输出。我们该怎么做
    getUserByName("nolan").then(function (user) {
      return getUserAccountById(user.id);
    }).then(function (userAccount) {
      // 在这里我们已经获取到了用户账号userAccount,
      // 但是我们也需要user对象时该怎么做?
    });    

    解决方案:
    function onGetUserAndUserAccount(user, userAccount) {
      return doSomething(user, userAccount);
    }
    
    function onGetUser(user) {
      return getUserAccountById(user.id).then(function (userAccount) {
        return onGetUserAndUserAccount(user, userAccount);
      });
    }
    
    getUserByName("nolan")
      .then(onGetUser)
      .then(function () {
      // at this point, doSomething() is done, and we are back to indentation 0
    });
Promise.prototype.catch(onRejected)
用于指定发生错误时的回调函数。catch 可以捕获
返回值:返回一个Promise,处理状态变为rejected的情况
参数:
    onRejected
        是一个函数,有一个参数,用来记录变成rejected状态返回的原因。
        当promise 状态变为rejected时被调用。

注意事项:
catch(rejectHandler) 
    等同于
.then(null, rejectHandler)或.then(undefined, rejectHandler)

但是 then(resolveHandler).catch(rejectHandler) 和then(resolveHandler, rejectHandler)
不是完全相同的。
区别在于:当使用then(resolveHandler, rejectHandler)格式时,如果resolveHandler本身抛出了错误,那么rejecthandler实际上不会捕获错误。所以更建议使用catch 而不是then的第二个参数。

示例:
    var p1 = new Promise((resolve, reject) => {
        resolve("one");
    });
    
    // catch函数中可以捕捉到resolveHandler 中的error并打印
    p1.then(function () {
        throw new Error("oh noes");
    }).catch(function (err) {
        console.log("err=", err); // Error: oh noes
    });
    
    // reject函数不能捕捉到resolveHandler中的error
    p1.then(function () {
        throw new Error("oh noes");
    }, function (err) {
        console.log("err=", err); 
    });
Promise.prototype.finally(onFinally)
用于指定不管 Promise 对象最后状态如何,都会执行的操作

finally本质上是then方法的特例
promise
.finally(() => {
  // 语句
});

// 等同于
promise
.then(
  result => {
    // 语句
    return result;
  },
  error => {
    // 语句
    throw error;
  }
);
返回值:返回一个Promise,这个Promise对象设置了 finally 回调函数
参数:Promise 结束后调用的函数,onFinally 这个函数不接收任何参数,它仅用于无论最终结果如何都要执行的情况。所以finally方法里面的操作,不应依赖于 Promise 的执行结果。
示例:
    promise
    .then(result => {···})
    .catch(error => {···})
    .finally(() => {···});

Promise.resolve(value)
用于将现有对象转为 Promise 对象
    new Promise(function (resolve, reject) {
      resolve(someSynchronousValue);
    }).then(/* ... */);
    等价于
    Promise.resolve(someSynchronousValue).then(/* ... */);

返回值:返回一个Promise 对象,这个Promise对象是被给定的值解析过的。
参数:
    value
        将被Promise对象解析的参数
        参数类型:
            Promise对象
            具有then方法的对象
            没有then方法的对象
            不带有任何参数

示例1:参数是一个Promise对象
    Promise.resolve将不做任何修改、原封不动地返回这个Promise对象

    var p = Promise.resolve([1,2,3]);
    console.log("p=", p); //"p=" [object Promise]
    console.log("p type= ", typeof(p)); // "p type= " "object"
    p.then(function(v) {
      console.log("v=",v); //"v=" Array [1, 2, 3]
      console.log("v type=",typeof(v)); //"v type=" "object"
    });
    
    var p2 =  Promise.resolve(p);
    console.log("p2=", p2); //"p2=" [object Promise]
    console.log("p2 type= ", typeof(p2)); //"p2 type= " "object"
    p2.then(function(v) {
      console.log("p2 v=",v); //"p2 v=" Array [1, 2, 3]
      console.log("p2 v type=",typeof(v)); //"p2 v type=" "object"
    });

    p2 == p
示例2:参数是一个具有then方法的对象
    返回的promise会采用这个thenable的对象的最终状态。

    let thenable = {
      then: function(resolve, reject) {
        resolve(42);
      }
    };
    
    let p = Promise.resolve(thenable);
    p.then(function(value) {
      console.log(value);  // 42
    });

    Promise.resolve方法会将thenable对象转为 Promise 对象,然后就立即执行thenable对象的then方法,thenable对象的then方法执行后,对象p的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42

示例3:参数是一个没有then方法的对象
    var p = Promise.resolve([1,2,3]);
    console.log("p=", p); //"p=" [object Promise]
    console.log("p type= ", typeof(p)); // "p type= " "object"
    p.then(function(v) {
      console.log("v=",v); //"v=" Array [1, 2, 3]
      console.log("v type=",typeof(v)); //"v type=" "object"
    });
    
    var p = Promise.resolve(123);
    console.log("p=", p); //"p=" [object Promise]
    console.log("p type= ", typeof(p)); // "p type= " "object"
    p.then(function(v) {
      console.log("v=",v); //"v=" 123
      console.log("v type=",typeof(v)); //"v type=" "number"
    });
    
    var p = Promise.resolve("123");
    console.log("p=", p); //"p=" [object Promise]
    console.log("p type= ", typeof(p)); // "p type= " "object"
    p.then(function(v) {
      console.log("v=",v); //"v=" "123"
      console.log("v type=",typeof(v)); //"v type=" "string"
    });

示例4:不带有任何参数
    var p = Promise.resolve();
    console.log("p=", p); //"p=" [object Promise]
    console.log("p type= ", typeof(p)); // "p type= " "object"
    p.then(function(v) {
      console.log("v=",v); //"v=" undefined
      console.log("v type=",typeof(v)); //"v type=" "undefined"
    });

注意事项:
    立即resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时
        //在下一轮“事件循环”开始时执行
        setTimeout(function () { 
          console.log("three");
        }, 0);
        //在本轮“事件循环”结束时执行
        Promise.resolve().then(function () {
          console.log("two");
        });
        //立即执行
        console.log("one");
    结果:
        "one"
        "two"
        "three"        
            
Promise.reject(reason)
返回值:返回一个Promise 对象,这个Promise 对象 带有状态是rejected的原因
参数:
    reason
        表示Promise被拒绝的原因
    new Promise(function (resolve, reject) {
      reject(someSynchronousReson);
    }).then(null,function(reason){
       //...
    });

等价于
    Promise.reject(someSynchronousReson)
    .then(null, function(reason) {
      //...
    });

    
示例:
    new Promise(function (resolve, reject) {
      reject("reject reason");
    }).then(null,function(reason){
            console.log(reason);//"reject reason"
    });
    
    Promise.reject("reject reason").then(null, function(reason) {
      console.log(reason); // "reject reason"
    });
    
    Promise.reject(new Error("reject reason")).then(null, function(error) {
      console.log(error); // Error: reject reason
    });

注意事项:与Promise.resolve不同的是Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。
    const thenable = {
      then(resolve, reject) {
        reject("出错了");
      }
    };
    
    Promise.reject(thenable)
    .catch(e => { //e不是reject抛出的“出错了”这个字符串,而是thenable对象。
      console.log(e === thenable) // true
    })
Promise.all(iterable)
用于将多个 Promise 实例,包装成一个新的 Promise 实例
返回值:返回一个新的promise对象,iterable中所有的promise都变成resolved状态时返回的 promise才会变为resolved状态; iterable中有一个promise变成rejected状态,promise就会变为rejected状态。
参数:
    iterable
    一个可迭代对象,eg Array 或 String

示例: iterable中所有的promise都变成resolved状态时返回的 promise才会变为resolved状态
    var p1 = new Promise((resolve, reject) => { 
      setTimeout(resolve, 1000, "one"); 
    }); 
    var p2 = new Promise((resolve, reject) => { 
      setTimeout(resolve, 2000, "two"); 
    });
    var p3 = new Promise((resolve, reject) => {
      setTimeout(resolve, 3000, "three");
    });
    const p = Promise.all([p1, p2, p3]).then(values => { 
      console.log(values); //["one", "two", "three"]
    }).catch(reason => {
      console.log(reason); //没执行
    });

    流程:p创建时为pending状态,当p1, p2, p3的状态都变成resolved时触发p变成resolved状态。
    p1    1s
    |----------|resolved                      
    p2    2s 
    |--------------------|resolved
    p3    3s 
    |------------------------------|resolved
                                   p resolved
                                   

示例:iterable中有一个promise变成rejected状态,promise就会变为rejected状态
    var p1 = new Promise((resolve, reject) => { 
      setTimeout(resolve, 1000, "one"); 
    }); 
    var p2 = new Promise((resolve, reject) => { 
      setTimeout(resolve, 2000, "two"); 
    });
    var p3 = new Promise((resolve, reject) => {
      reject("reject");
    });
    const p = Promise.all([p1, p2, p3]).then(values => { 
      console.log(values); //没执行
    }).catch(reason => {
      console.log(reason); //"reject"
    });    

    流程:p创建时为pending状态,p3先执行完,p3的状态变成rejected时触发p变成rejected状态。
    p1    1s
    |----------|resolved                      
    p2    2s 
    |--------------------|resolved
    p3
    |-|rejected
      p rejected
      

示例:如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法
    var p1 = new Promise((resolve, reject) => { 
          setTimeout(resolve, 1000, "one"); 
        }); 
        var p2 = new Promise((resolve, reject) => { 
          setTimeout(resolve, 2000, "two"); 
        });
        var p3 = new Promise((resolve, reject) => {
          reject("reject");
        }).catch(reason => {
          console.log(reason); //reject
        });
        const p = Promise.all([p1, p2, p3]).then(values => { 
          console.log(values); // ["one", "two", undefined]
        }).catch(reason => {
          console.log(reason); //没执行
        });    


    流程:p创建时为pending状态,p3先执行完,p3的状态变成rejected时,调用自己定义的catch函数抛出错误,不会触发p变成rejected状态。当p1 和 p2 也执行完时,触发p变成resolved状态
    p1    1s
    |----------|resolved                      
    p2    2s 
    |--------------------|resolved
    p3
    |-|rejected
                           |p resolved

示例:如果传入的参数是一个空的可迭代对象,则返回一个resolved状态的 Promise 
    const p = Promise.all([]).then(values => { //p创建时状态就为resolved
      console.log(values); // []
    });
Promise.race(iterable)
同样是将多个 Promise 实例,包装成一个新的 Promise 实例
返回值:返回一个新的promise对象,一旦iterable中的某个promise变为resolved或rejected状态,返回的 promise就会变为resolved或rejected状态。谁最先执行完就返回谁的状态
参数:
    iterable
    一个可迭代对象,eg Array 或 String

示例: 一旦iterable中的某个promise变为resolved状态,返回的 promise就会变为resolved状态。
    var p1 = new Promise((resolve, reject) => { 
      setTimeout(resolve, 1000, "one"); 
    }); 
    var p2 = new Promise((resolve, reject) => { 
      setTimeout(resolve, 2000, "two"); 
    });
    var p3 = new Promise((resolve, reject) => {
      setTimeout(resolve, 3000, "three");
    });
    const p = Promise.race([p1, p2, p3]).then(values => { 
      console.log(values); //["one", "two", "three"]
    }).catch(reason => {
      console.log(reason); //没执行
    });

流程:p创建时为pending状态,p1先执行完,p1的状态都变成resolved时触发p变成resolved状态。
p1    1s
|----------|resolved
           p resolved                      
p2    2s 
|--------------------|resolved
p3    3s 
|------------------------------|resolved
                               
                                   
示例:一旦iterable中的某个promise变为rejected状态,返回的 promise就会变为rejected状态。
var p1 = new Promise((resolve, reject) => { 
  setTimeout(resolve, 1000, "one"); 
}); 
var p2 = new Promise((resolve, reject) => { 
  setTimeout(resolve, 2000, "two"); 
});
var p3 = new Promise((resolve, reject) => {
  reject("reject");
});
const p = Promise.all([p1, p2, p3]).then(values => { 
  console.log(values); //没执行
}).catch(reason => {
  console.log(reason); //"reject"
});    

流程:p创建时为pending状态,p3先执行完,p3的状态变成rejected时触发p变成rejected状态。
p1    1s
|----------|resolved                      
p2    2s 
|--------------------|resolved
p3
|-|rejected
  p rejected

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

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

相关文章

  • ES6-7

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

    mudiyouyou 评论0 收藏0
  • 通过 ES6 Promise 和 jQuery Deferred 的异同学习 Promise

    摘要:和和都有和,但是略有不同。实际上返回的是一个对象。和添加的回调,添加的回调。所以在调用成功的情况下执行添加的回调,调用失败时执行添加的回调。,产生对象并,产生对象并,然后继续处理,的语法糖,和的差不多但不同。 Deferred 和 Promise ES6 和 jQuery 都有 Deffered 和 Promise,但是略有不同。不过它们的作用可以简单的用两句话来描述 Deffere...

    Yujiaao 评论0 收藏0
  • es6 - Promise

    摘要:所谓异步编程中的异步是相对于同步的概念的。是一系列异步编程规范的统称。如果中的回调函数返回一个值,那么返回的将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。参考介绍基础篇深入理解与异步编程。 es6 promise与异步编程 对于一些还不具备大量编程经验的朋友来说,promise可能是es6比较难以掌握的点。首先是很多名词,比如Promises,es6 Promise,...

    wemallshop 评论0 收藏0
  • JavaScript 异步

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

    tuniutech 评论0 收藏0
  • 浅谈ES6原生Promise

    摘要:如果有错误,则到的第二个回调函数中,对错误进行处理。假设第一个的第一个回调没有返回一个对象,那么第二个的调用者还是原来的对象,只不过其的值变成了第一个中第一个回调函数的返回值。 ES6标准出炉之前,一个幽灵,回调的幽灵,游荡在JavaScript世界。 正所谓: 世界本没有回调,写的人多了,也就有了})})})})})。 Promise的兴起,是因为异步方法调用中,往往会出现回调函数一...

    yedf 评论0 收藏0
  • ES6Promise:要优雅,也要浪漫

    摘要:就算改变已经发生了,即使再对对象添加回调函数,也会立即得到这个结果。方法接收个参数,第一个参数是状态的回调函数,第二个参数可选是状态的回调函数。简单来讲,就是能把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。 在ECMAScript 6标准中,Promise被正式列为规范,Promise,字面意思就是许诺,承诺,嘿,听着是不是很浪漫的说?我们来探究一下这个浪...

    weizx 评论0 收藏0

发表评论

0条评论

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