美文网首页程序员大话前端
Promise对象了解一下

Promise对象了解一下

作者: fenerchen | 来源:发表于2018-08-09 18:04 被阅读7次

    是什么

    Promise是异步编程的一种解决方案。

    特点

    1、对象的状态不受外界影响。Promise对象代表一个异步操作,有3中状态:Pending(进行中)、Fulfilled(已成功)、Rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
    2、一旦状态改变就不会再变,任何时候都可以得到这个结果。Prmise对象的状态改变只有两种可能:从PendingFulfilled,从PendingRejected。只要这两种情况发生,状态就凝固了,不会再变,而是一直保持这个结果,此时为Reaolved(已定型)

    优缺点

    优点
    1、将异步操作以同步操作的流程表达出来,避免层层嵌套回调函数
    2、接口统一,控制异步操作更加容易
    缺点
    1、无法取消Promise,一旦创建就会立即执行。
    2、如果不设置回调函数,错误无法反应到外部
    3、当处于Pending状态时,无法得知进展到哪一个阶段(刚开始还是即将完成)

    基本用法

    Promise对象是一个构造函数,用来生成Promise实例。

    let promise=new Promise((resolve,reject)=>{
        if(/*异步操作成功*/){
            resolve(val)
        }else{
            reject(err)
        }
    })
    
    promise.then(
        val=>console.log(val,'异步操作成功调用该函数'),
        err=>console.log(err,'异步操作失败')
    )
    

    Promise构造函数的参数是一个函数,该函数接受两个参数,也均为函数,分别是resolve和rejectresolve的作用是将Promise对象的状态从未完成变为成功,在异步操作成功时调用,并将异步操作的结果作为参数传递出去,而reject则是用于失败的情况。当Promise实例生成后,可以用then方法分别指定Resolve状态和Rejected状态的回调函数。.then对象的第一个函数参数就是处理resolve的情况,第二个函数参数是处理reject的情况

    Promise新建后会立即执行

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

    同步任务栈为空时,才去异步任务队列中取出回调函数去执行

    then方法的作用是为Promise实例添加状态改变时的回调函数。返回的仍然是一个Promise对象但是它是新的对象,不再是原来的那个实例。因此可以采用链式非常重要的一点采用链式的then可以指定一组按次序调用的回调函数后面的then等前面的then(也就是新的Promise对象状态变化后在执行,如果前面的then状态是resolve那么就执行第一个参数函数,否则就执行第二个参数函数)**

    then链式操作

    const timeout = ms => new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve();
        }, ms);
    });
    
    const ajax1 = () => timeout(2000).then(() => {
        console.log('1');
        return 1;
    });
    
    const ajax2 = () => timeout(1000).then(() => {
        console.log('2');
        return 2;
    });
    
    const ajax3 = () => timeout(2000).then(() => {
        console.log('3');
        return 3;
    });
    var sequence = Promise.resolve();//返回一个状态是resolveed的promise对象
    
    var data=[]
    //链式操作,按顺序来
    sequence.then(ajax1).then(val=>{//如果ajax1的状态为resolved那么其返回的值就入栈,其他同理
        data.push(val)
    }).then(ajax2).then(val=>{
        data.push(val)
    }).then(ajax3).then(val=>{
        data.push(val)
        console.log(data)
    })
    //1
    //2
    //3
    //[1,2,3]
    
    

    注意事项

    1、resolve(p),p还是个promise对象时,那么最终状态有p来决定。

    const p1 = new Promise(function (resolve, reject) {
      setTimeout(() => reject(new Error('fail')), 3000)
    })
    
    const p2 = new Promise(function (resolve, reject) {
      setTimeout(() => resolve(p1), 1000)
    })
    
    
     p2 .then(result => console.log(result))
      .catch(error => console.log(error))
    // Error: fail
    

    上面代码中,p1是一个Promise,3 秒之后变为rejectedp2的状态在 1 秒之后改变,resolve方法返回的是p1。由于p2返回的是另一个Promise,导致p2自己的状态无效了,由p1的状态决定p2的状态。所以,后面的then语句都变成针对后者(p1)。又过了 2 秒,p1变为rejected,导致触发catch方法指定的回调函数。

    2、调用resolvereject不会终结Promise的参数函数执行

    new Promise((resolve, reject) => {
      resolve(1);
      console.log(2);
    }).then(r => {
      console.log(r);
    });
    // 2
    // 1
    

    一般来说,调用resolve或reject以后,Promise 的使命就完成了,后继操作应该放到then方法里面,而不应该直接写在resolve或reject的后面。所以,最好在它们前面加上return语句,这样就不会有意外。

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

    3、尽量使用catch来捕获错误,而非reject第二个参数函数
    Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。

    getJSON('/post/1.json').then(function(post) {
      return getJSON(post.commentURL);
    }).then(function(comments) {
      // some code
    }).catch(function(error) {
      // 处理前面三个Promise产生的错误
    });
    
    
    // bad
    promise
      .then(function(data) {
        // success
      }, function(err) {
        // error
      });
    
    // good
    promise
      .then(function(data) { //cb
        // success
      })
      .catch(function(err) {
        // error
      });
    

    与传统try/catch的不同:如果没有使用catch方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应
    4、如果 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) });
    // ok
    

    Promise.resolve(参数)

    (1)参数是一个 Promise 实例

    如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。

    (2)参数是一个thenable对象
    Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行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 对象。

    done()和finally()的区别

    done()处于回调链的尾端,保证抛出任何肯能的错误,向全局抛出。
    finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。

    promise
    .then(result => {···})
    .catch(error => {···})
    .finally(() => {···});
    

    上面代码中,不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。可以使用finally关掉服务器。

    阿里笔试题目 -- 实现mergePromise函数

    //实现mergePromise函数,把传进去的数组顺序先后执行,
    //并且把返回的数据先后放到数组data中
    
    const timeout = ms => new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve();
        }, ms);
    });
    
    const ajax1 = () => timeout(2000).then(() => {
        console.log('1');
        return 1;
    });
    
    const ajax2 = () => timeout(1000).then(() => {
        console.log('2');
        return 2;
    });
    
    const ajax3 = () => timeout(2000).then(() => {
        console.log('3');
        return 3;
    });
    
    const mergePromise = ajaxArray => {
        // 在这里实现你的代码
        var data = [];
        var sequence = Promise.resolve();
        ajaxArray.forEach(function(item){//使用链式then,每次的then都赋给sequence,从而达到连接的作用。
            sequence = sequence.then(item).then(function(res){
                 data.push(res);
                 return data;
            }); 
        })
    
        return sequence;
    };
    
    mergePromise([ajax1, ajax2, ajax3]).then(data => {
        console.log('done');
        console.log(data); // data 为 [1, 2, 3]
    });
    
    // 分别输出
    // 1
    // 2
    // 3
    // done
    // [1, 2, 3]
    

    相关文章

      网友评论

        本文标题:Promise对象了解一下

        本文链接:https://www.haomeiwen.com/subject/karcbftx.html