关闭

关于Promise的总结

标签: javascriptes6promise异步setTimeout
775人阅读 评论(4) 收藏 举报
分类:

Promise是抽象异步处理对象以及对其进行各种操作的组件,它的功能是可以将复杂的异步处理轻松的模式化


创建Promise对象的方法

创建对象的方法

1.new Promise(fn)返回一个Promise对象

2.在fn中指定异步等处理

  • 处理结果正确的时候,调用resolve(处理结果值)
  • 处理结果错误的时候,调用reject(Error对象)

3.使用 promise.then() 实例方法,对Promise的实例对象设置其在resolve/reject时调用的回掉函数(一次调用),当然如果只想处理异常可以采用 promise.catch(onRejected)或者promise.then(undefined, onRejected)

举例

调用asyncFunction的时候返回的是一个Promise的实例对象,所以在调用完asyncFunction的时候使用了then,设置了成功与失败时候的回掉函数

function asyncFunction() {
  return new Promise(function(resolve, rejecct) {
    setTimeout(function() {
      resolve('Hello World');
    }, 16);
  });
}

asyncFunction().then(function(value) {
  console.log("Fulfilled", value);
}).catch(function(error) {
  console.log("error", error);
});

Promise的实例对象的三种状态

通过new Promise返回的Promise对象,有以下三种状态:

  • has-resolution-Fulfilled,resolve(成功)时,会调用onFulfilled
  • has-rejection - Rejected,reject(失败)时,会调用onRejected
  • unresolved-pending,既不是resolve也不是reject的状态,也就是Promise对象刚被创建后的初始化状态等

Fulfilled和Rejected这两个中的任一状态都可以表示为Settled(不变的)。

创建XHR的Promise对象

function getURL(url) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.open("get", url);
    xhr.onload = function() {
      if(xhr.status == 200) {
        resolve(xhr.responseText);
      }else {
        reject("状态错误");
      }
    };

    xhr.onerror = function() {
      reject("出错");
    }
    xhr.send();
  });
}
//https://httpbin.org/status/500
//https://httpbin.org/get   
getURL('https://httpbin.org/get').then((value) => {
  console.log(value);
}).catch((error) => {
  console.log(error);
});

创建Promise实例对象的静态方法

Promise.resolve

它可以认为是

new Promise(function(resolve, reject) {
  resolve();
})

Promise.resolve的返回值是一个Promise对象,所以继续可以用then调用,所以Promise.resolve也可以认为是new Promise的快捷形式

Promise.resolve的另外一个作用就是将thenable对象转换为promise对象,thenable对象就是指的是一个具有.then方法的对象,这种将thenable对象转换为promise对象的机制要求thenable对象所拥有的then方法应该和Promise所拥有的then方法具有相同的功能和处理过程,再将thenabel对象转换为promise对象的时候,还会巧妙的利用thenable对象原来所具有的then方法

thenable最简单的例子就是jQuery.ajax(),它的返回值就是thenable的,将thenable转换为Promise对象的时候,就可以调用then和catch方法

/*将thenable对象转换为Promise对象*/
var promise = Promise.resolve($.ajax('https://httpbin.org/get'));
promise.then(function(value) {
  console.log(value);   //jQuery ajax的返回值是一个具有.then方法的jq XHR Object对象,这个对象继承了来自Deferred Object的方法和属性
});
var ary = [1, 2, 3, 4, 5];
for(var i = 0; i < ary.length; i++) {
    Promise.resolve(ary[i]).then(function(d) {
        console.log(d);
    });
}

输出结果为:

1 2 3 4 5

Promise.reject

它相当于

new Promise(function(resolve, reject) {
  reject(new Error("出错了"));
});

备注

Promise保证了每次的调用都是以异步的方式进行的,所以在实际代码中不需要调用setTimeout来自己实现异步

    function test() {
        console.log("test-1");
        return new Promise(function(resolve, reject) {
            console.log("test-2");
            resolve("test-test");
        });
    }

    test().then(function(data) {
        console.log(data);
    }, function() {
        console.log("error");
    });

    console.log("test-outer");

结果:

test-1
test-2
test-outer
test-test


处理多个异步请求

Peomise方法链


    promise.then(function taskA(value) {
        //task A
    }).then(function taskB(value) {
        //task B
    }).then(function taskC(value) {
        //task C
    }).catch(function onRejected(error) {
        console.log(error);
    });

在每一个task的方法中,都可以包含一个return语句,返回的值也可以是一个Promise对象,return的值会Promise.resolve(return的返回值);进行相应的包装处理,因此不管回掉函数中返回一个怎样的值最终then的结果都是返回一个新创建的promise对象

catch

调用catch的时候,只是promise.then(undefined, onRejected)方法的一个别名而已,这个方法用来注册当promise对象状态变为Rejected时的回掉函数

then和catch的处理错误的区别:

  1. .then和catch都会创建并返回一个新的Promise对象。Promise实际上每次在方法链上增加一次处理的时候所操作的都不是完全相同的promise对象
  2. .then(resolve, reject)其中这个reject并不能捕获resolve中的错误,而.catch(reject)总会捕获它前面出现的错误
  3. 使用.then(null, reject)可以完成.catch同样的工作,只不过使用.catch的意图更加明确,易于理解

总结:
1. 使用 promise.then(onFulfilled, onRejected) 的话
• 在 onFulfilled 中发生异常的话,在 onRejected 中是捕获不到这个异常的。
2. 在 promise.then(onFulfilled).catch(onRejected) 的情况下
• then 中产生的异常能在 .catch 中捕获
3. .then 和 .catch 在本质上是没有区别的
• 需要分场合使用。

Promise.all

Promise.all接收一个Promise对象的数组作为参数,当这个数组的所有Promise对象全部变为resolve或reject的时候,它才回去调用.then方法

function getURL(URL) {
  return new Promise(function(resolve, reject) {
    var req = new XMLHttpRequest();
    req.open("Get", URL, true);
    req.onload = function() {
      if (req.status === 200) {
        resolve(req.responseText);
      }else {
        reject(new Error(req.statusText));
      }
    };
    req.onerror = function() {
      reject(new Error(req.statusText));
    };
    req.send();
  });
}

var request = {
  comment : function getComment() {
    return getURL('https://azu.github.io/promises-book/json/comment.json').then(JSON.parse);
  },
  people: function getPeople() {
    return getURL('https://azu.github.io/promises-book/json/people.json').then(JSON.parse);
  }
};

function main() {
  return Promise.all([request.comment(), request.people()]);
}

main().then(function(value) {
  console.log(value);
}).catch(function(error) {
  console.log(error);
});

Promise.all([request.comment(), request.people()])会同时开始执行,而且每个promise的结果(resolve或者reject时传递的参数值),和传递给Promise.allpromise数组的顺序是一致的,也就说这里面的then中的value的值,也是是得到的两个JSON对象也是按照[comment,people]的进行排列的

所以传递给Promise.allPromise不是一个个顺序执行的,而是同时开始的并行完成的

Promise.race

Promise.race使用的方法和Promise.all一样对多个Promise对象进行并行处理,但是Promise.all在接收到所有的对象的状态都变成FullFilled或者Reject状态之后才会进行相应的处理,与之相对的是Promise.race只要有一个promise对象进入FulFilled状态或者Rejected状态的话,就会进行后面的处理

function tst1() {
  return new Promise(function(resolve, rejecct) {
    resolve(20);
  });
}

function tst2() {
  return new Promise(function(resolve, rejecct) {
    resolve(88);
  })
};

Promise.race([tst1(), tst2()]).then(function(data) {
  console.log(data);
});

输出的结果:

20

function timerPromisefy(delay) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve(delay);
    }, delay);
  });
}

Promise.race([timerPromisefy(1), timerPromisefy(32), timerPromisefy(64), timerPromisefy(128)]).then(function(data) {
  console.log(data); 
});  

输出的结果:

1

换成下面的这样:

Promise.all([timerPromisefy(1), timerPromisefy(32), timerPromisefy(64), timerPromisefy(128)]).then(function(data) {
  console.log(data); 
}); 

输出的结果:

[1, 32, 64, 128]


补充

事件的注册顺序如下:

setImmediate - setTimeout - promise.then - process.nextTick

因此,我们得到了优先级关系如下:

process.nextTick > promise.then > setTimeout > setImmediate

setTimeout(function(){console.log(4)},0);
new Promise(function(resolve){
    console.log(1)
    for( var i=0 ; i<10000 ; i++ ){
        i==9999 && resolve()
    }
    console.log(2)
}).then(function(){
    console.log(5)
});
console.log(3);

输出结果:

1 2 3 5 4


参考:javascript-promise-book

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:54249次
    • 积分:1704
    • 等级:
    • 排名:千里之外
    • 原创:119篇
    • 转载:9篇
    • 译文:0篇
    • 评论:7条
    博客专栏
    最新评论