zoukankan      html  css  js  c++  java
  • ES6 Promise

    1》介绍

    1.异步编程的一种解决方案
    2.简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
    从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。
    3.特点:
    1>.对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
    只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
    2>Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。
    只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。
    4.Promise 缺点
    1>无法取消Promise,一旦新建它就会立即执行,无法中途取消。
    2>其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
    3>第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

    2》基本用法

    1.Promise对象是一个构造函数,用来生成Promise实例;构造函数的含有两个函数参数 resolve与reject
    resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
    reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

    var promise = new Promise(function(resolve, reject) {
        // ... some code
        if (/* 异步操作成功 */){
          resolve(value);
        } else {
          reject(error);
        }
      });

    2.Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
    then方法可以接受两个回调函数作为参数。
    第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。第二个函数是可选的,不一定要提供。
    这两个函数都接受Promise对象传出的值作为参数。即调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。

    promise.then(function(value) {
      // resolve
    }, function(error) {
      // reject
    });
    
    function timeout(ms) {
      return new Promise(function(resolve,reject){
        setTimeout(resolve('done'), ms);
      })
    }
    timeout(100).then(function(value){
      console.log(value)
    });

    3.Promise 新建后就会立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。

    var promise = new Promise(function(resolve, reject) {
      console.log('Promise');
      resolve();
    });
    promise.then(function() {
      console.log('resolved');
    });
    console.log('Hi!');   //Promise   Hi!   resolved.

    4.调用resolve或reject并不会终结 Promise 的参数函数的执行。因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。

    new Promise((resolve, reject) => {
      resolve(1);
      console.log(2);
    }).then(r => {
      console.log(r);
    }); //2 1
    
    改进
    new Promise((resolve, reject) => {
      return resolve(1);
      // 后面的语句不会执行
      console.log(2);
    })

    3》Promise.prototype等方法

    1.Promise.prototype.then()
    链式的then,可以指定一组按照次序调用的回调函数。
    这时,前一个回调函数,return有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。
    promise.then().then()....

    2.Promise.prototype.catch()
      <1>Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。

    const promise = new Promise(function(resolve, reject) {
      throw new Error('test');
    });
    promise.catch(function(error) {
      console.log(error);
    });

      <2>如果 Promise 状态已经变成resolved,再抛出错误是无效的。

    const promise = new Promise(function(resolve, reject) {
      resolve('ok');
      throw new Error('test');
    });
    promise.then(function(value) { console.log(value) }).catch(function(error) { console.log(error) });

      <3>Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。

    promise.then(function(post) {
      return otherpromise;
    }).then(function(comments) {
      // some code
    }).catch(function(error) {
      // 处理前面三个Promise产生的错误
    });

      <4>Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”。

    const someAsyncThing = function() {
      return new Promise(function(resolve, reject) {
        // 下面一行会报错,因为x没有声明
        resolve(x + 2);
      });
    };
    someAsyncThing().then(function() {
      console.log('everything is great');
    });
    setTimeout(() => { console.log(123) }, 2000);

    3.Promise.prototype.finally()

      finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作;且finally方法的回调函数不接受任何参数
      promise.then(result => {···}).catch(error => {···}).finally(() => {···});

      实现:https://github.com/matthew-andrews/Promise.prototype.finally/blob/master/finally.js

    4.Promise.all()

      用于将多个 Promise 实例,包装成一个新的 Promise 实例;接受一个数组作为参数 Promise.all([p1, p2, p3]);
      区别:并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调

      https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/130

    Promise.all([runAsync1(), runAsync2(), runAsync3()]).then(function(results){
          console.log(results);  
      });

    5.Promise.race() 

      用于将多个 Promise 实例,包装成一个新的 Promise 实例接受一个数组作为参数 Promise.all([p1, p2, p3]);
      all方法的效果实际上是「谁跑的慢,以谁为准执行回调」,那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」

      https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/140

    function runAsync1(){
          var p = new Promise(function(resolve, reject){
              //做一些异步操作
              setTimeout(function(){
                  console.log('异步任务1执行完成');
                  resolve('随便什么数据1');
              }, 1000);
          });
          return p;            
        }
        function runAsync2(){
          var p = new Promise(function(resolve, reject){
              //做一些异步操作
              setTimeout(function(){
                  console.log('异步任务2执行完成');
                  resolve('随便什么数据2');
              }, 2000);
          });
          return p;            
        }
        function runAsync3(){
          var p = new Promise(function(resolve, reject){
              //做一些异步操作
              setTimeout(function(){
                  console.log('异步任务3执行完成');
                  resolve('随便什么数据3');
              }, 2000);
          });
          return p;            
        }
    
        Promise.all([runAsync1(), runAsync2(), runAsync3()]).then(function(results){
            console.log(results);
        });
    
        Promise.race([runAsync1(), runAsync2(), runAsync3()]).then(function(results){
            console.log(results);
        });

    6.Promise.resolve()
    将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用。
    (1)参数是一个 Promise 实例
    如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
    (2)参数是一个thenable对象

      Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。
      thenable对象指的是具有then方法的对象,比如下面这个对象。

      

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

    (3)参数不是具有then方法的对象,或根本就不是对象
      如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。

    const p = Promise.resolve('Hello');
          p.then(function (s){
          console.log(s)
    });// Hello

    (4)不带有任何参数
      Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。
      需要注意的是,立即resolve的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。

    setTimeout(function () {
      console.log('three'); //下一轮“事件循环”开始时执行
    }, 0);
    Promise.resolve().then(function () {
      console.log('two'); //本轮“事件循环”结束时执行
    });
    console.log('one'); // one   two   three

    7.Promise.reject()

      Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
      参数用法同上
      const p = Promise.reject('出错了');
      // 等同于
      const p = new Promise((resolve, reject) => reject('出错了'))

    8.Promise.try()
      让同步函数同步执行,异步函数异步执行

    4》案例:

      案例1:

    const promise = new Promise((resolve, reject) => {
        console.log(1);
        resolve();
        console.log(2);
    })
    
    promise.then(() => {
        console.log(3);
    })
    
    console.log(4);
    

      首先 Promise 新建后立即执行,所以会先输出 1,2,而 Promise.then() 内部的代码在 当次 事件循环的 结尾 立刻执行 ,所以会继续输出4,最后输出3。

    案例2:

      

    const promise = new Promise((resolve, reject) => {
        resolve('success1');
        reject('error');
        resolve('success2');
    });
    
    promise.then((res) => {
        console.log('then:', res);
    }).catch((err) => {
        console.log('catch:', err);
    })
    

      resolve 函数将 Promise 对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

      reject 函数将 Promise 对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

           而一旦状态改变,就不会再变。所以 代码中的reject('error'); 不会有作用。

      Promise 只能 resolve 一次,剩下的调用都会被忽略。所以 第二次的 resolve('success2'); 也不会有作用。因此:then: success1

    案例3:

    Promise.resolve(1)
      .then(2)
      .then(Promise.resolve(3))
      .then(console.log)
    

      Promise.resolve 方法的参数如果是一个原始值,或者是一个不具有 then 方法的对象,则 Promise.resolve 方法返回一个新的 Promise 对象,状态为resolved,Promise.resolve 方法的参数,会同时传给回调函数。

      then 方法接受的参数是函数,而如果传递的并非是一个函数,它实际上会将其解释为 then(null),这就会导致前一个 Promise 的结果会穿透下面。因此:1

     

  • 相关阅读:
    学 Win32 汇编[28]
    C#将数据集DataSet中的数据导出到EXCEL文件的几种方法
    FFmpeg 学习(四):FFmpeg API 介绍与通用 API 分析
    Android 代码混淆配置总结
    Android 视频播放器 (三):使用NBPlayer播放直播视频
    Android 视频播放器 (二):使用MediaPlayer播放视频
    Android 展示控件之Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系
    Android 视频播放器 (一):使用VideoView播放视频
    JavaCV 学习(二):使用 JavaCV + FFmpeg 制作拉流播放器
    Android Studio 常见问题及解决方法
  • 原文地址:https://www.cnblogs.com/changxue/p/8393107.html
Copyright © 2011-2022 走看看