《JavaScript Promise迷你书》读书笔记 - devnote
promise定义
Promise是抽象异步处理对象以及对其进行各种操作的组件
简言之,使用Promise就是将javascript中异步的方式变换成同步来操作。Promise则是把类似的异步处理对象和处理规则进行规范化, 并按照采用统一的接口来编写,规定方法之外的写法都会报错。简单的示例:
var promise = getAsyncPromise("fileA.txt"); //处于Pending状态,既不是resolve也不是reject的状态。是promise对象刚被创建后的初始化状态 promise.then(function(result){ // 获取文件内容成功时的处理 成功时状态为onFulfilled }).catch(function(error){ // 获取文件内容失败时的处理 失败时状态为onRejected });
其中,then
和catch
代表函数执行成功和失败的预设操作
构建promise对象,使用new
关键字
var promise = new Promise(function(resolve, reject) { // 异步处理 // 处理结束后、调用resolve 或 reject });
对象方法 then
promise.then(onFulfilled, onRejected); //onFulfilled函数会在promise对象的revolve状态调用,onRejected为在promise对象reject状态下调用 promise.catch(function());//catch用来代替onRejected抛出错误
promise对象中内置部分静态方法
如Promise.all()
, Promise.race
,Promise.resolve()
,Promise.reject
等
创建XHR的promise对象
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);//传入resolve中的参数会在状态改变的时候,传到then中 } else {reject(new Error(req.statusText)); } }; req.onerror = function () { reject(new Error(req.statusText)); }; req.send();});}// 运行示例var URL = "http://httpbin.org/get";getURL(URL).then(function onFulfilled(value){console.log(value);}).catch(function onRejected(error){console.error(error);});
Promise.resolve
作用1. Promise.resolve 是 new Promise(func)的快捷方式,如Promise.resolve(42);
与 new Promise(function(resolve){ resolve(42);});
作用2. 将thenable
对象转换为promise对象。thenable
指的是一个具有 .then
方法的对象。
Promise.reject
Promise.reject(new Error("出错了"))
等价于
new Promise(function(resolve,reject){ reject(new Error("出错了"));});
使用
Promise.reject(new Error("BOOM!")).catch(function(error){ console.error(error);});
promise对象立刻进入resolve状态
var promise = new Promise(function (resolve){ console.log("inner promise"); // 1 resolve(42);});promise.then(function(value){ console.log(value); // 3});console.log("outer promise"); // 2
输出结果为 1,2,3; 即使resolve立即执行,得出的结果也在下一个时间环里,需要等到下一周期才能执行
1.绝对不能对异步回调函数(即使在数据已经就绪)进行同步调用。
2.如果对异步回调函数进行同步调用的话,处理顺序可能会与预期不符,可能带来意料之外的后果。
3.对异步回调函数进行同步调用,还可能导致栈溢出或异常处理错乱等问题。
4.如果想在将来某时刻调用异步回调函数的话,可以使用setTimeout
等异步API。
对比三段代码:
第一段:直接判断文件是否加载完成
function onReady(fn) { var readyState = document.readyState; if (readyState === 'interactive' || readyState === 'complete') { fn(); } else { window.addEventListener('DOMContentLoaded', fn); }}onReady(function () { console.log('DOM fully loaded and parsed');});console.log('==Starting==');
第二段:使用setTimeout转同步为异步操作
function onReady(fn) { var readyState = document.readyState; if (readyState === 'interactive' || readyState === 'complete') { setTimeout(fn, 0); //使用setTimeout转化同步函数为异步函数 } else { window.addEventListener('DOMContentLoaded', fn); }}onReady(function () { console.log('DOM fully loaded and parsed');});console.log('==Starting==');
第三段:使用promise的resolve将统一为异步的方式,减少判断
function onReadyPromise() { return new Promise(function (resolve, reject) { var readyState = document.readyState; if (readyState === 'interactive' || readyState === 'complete') {resolve(); } else {window.addEventListener('DOMContentLoaded', resolve); } });}onReadyPromise().then(function () { console.log('DOM fully loaded and parsed');});console.log('==Starting==');
关于传递参数promise的写法
function doubleUp(value) { return value * 2;}function increment(value) { return value + 1;}function output(value) { console.log(value);// => (1 + 1) * 2}var promise = Promise.resolve(1);//构造一个返回参数为1的promise对象promise .then(increment) //此时increment函数中传的vaule值为1 .then(doubleUp) //此时doubleUp函数中传的vaule值为2 .then(output) //此时doubleUp函数中传的vaule值为 4 .catch(function(error){ // promise chain中出现异常的时候会被调用 console.error(error); });
Promise.resolve
和Promise.reject
会对函数中return返回的值进行包装,最终then
返回的结果都是新创建的promise
对象
Promise.all
的使用
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('http://azu.github.io/promises-book/json/comment.json').then(JSON.parse); }, people: function getPeople() {return getURL('http://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
的promise数组是同时开始执行的
// `delay`毫秒后执行resolvefunction timerPromisefy(delay) { return new Promise(function (resolve) { setTimeout(function () {resolve(delay); }, delay); });}var startDate = Date.now();// 所有promise变为resolve后程序退出Promise.all([ timerPromisefy(1), timerPromisefy(32), timerPromisefy(64), timerPromisefy(128)]).then(function (values) { console.log(Date.now() - startDate + 'ms'); // 約128ms console.log(values); // [1,32,64,128]});
Promise.race
只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理
// `delay`毫秒后执行resolvefunction timerPromisefy(delay) { return new Promise(function (resolve) { setTimeout(function () {resolve(delay); }, delay); });}// 任何一个promise变为resolve或reject 的话程序就停止运行Promise.race([ timerPromisefy(1), timerPromisefy(32), timerPromisefy(64), timerPromisefy(128)]).then(function (value) { console.log(value); // => 1});//代码第二段 var winnerPromise = new Promise(function (resolve) { setTimeout(function () {console.log('this is winner');resolve('this is winner'); }, 4); });var loserPromise = new Promise(function (resolve) { setTimeout(function () {console.log('this is loser');resolve('this is loser'); }, 1000); });// 第一个promise变为resolve后程序停止Promise.race([winnerPromise, loserPromise]).then(function (value) { console.log(value); // => 'this is winner'});
不能进行错误处理的onRejected
function throwError(value) { // 抛出异常 throw new Error(value);}// <1> onRejected不会被调用function badMain(onRejected) { return Promise.resolve(42).then(throwError, onRejected);}// <2> 有异常发生时onRejected会被调用function goodMain(onRejected) { return Promise.resolve(42).then(throwError).catch(onRejected);}// 运行示例badMain(function(){ console.log("BAD");});goodMain(function(){ console.log("GOOD");});
说明:上面代码中<1>中throwError 抛出了异常,onRejected 指定的函数也不会被调用
.then 和 .catch 都会创建并返回一个 新的 promise对象。 Promise实际上每次在方法链中增加一次处理的时候所操作的都不是完全相同的promise对象。