上文中我们提到了如何用预加载来提前获取图片等资源,当我们获取资源的时候常常会有资源获取失败的情况(例如网络不通、资源地址失效、资源地址不正确等),我们可以用try catch来处理这种异常的情况,当然更多的是使用ES6新的Promise对象。在new一个Promise时会传入两个函数,resolve用来处理正常流程,reject是处理异常的方法,最后通过示例化的then方法来启动。我们可以来简单实践一下:
var promise = new Promise(function(resolve,reject){ var img = new Image(); img.onload = function(){ resolve(this); //通过实例的then传进来的correct方法 } img.onerror = function(){ reject("加载失败"); //通过实例的then传进来的error方法 } img.src = "./image/test.jpg" }) promise.then(correct(),error()); //通过实例开始处理逻辑 //正常加载调用此方法 function correct(data){ console.log(data); } //加载异常时调用此方法 function error(errorInfo){ console.log(errorInfo); }
在这里要注意catch和then的区别是catch会对整个promise做异常捕获,包括resolve。而reject只是对我们已预知的异常,根据具体业务逻辑做的异常处理。
但是这里有个问题要注意,对于promise内部的异步方法,promise.then和promise.catch是捕获不到的,因为回调方法setTimeout会放在异步方法catch和then之后运行。我们可以测试一下。
let p = new Promise((resolve, reject) => { setTimeout(() => { throw "error"; //没有被p.catch捕获到,直接报错 }, 0); }); p.catch(err => { console.log("catch " + err); // 不会被执行 });
在上面的代码运行结果中并没有正确的打印输出异常,而是报了Uncaught error异常未捕获的错,说明catch捕获异常放在异步函数之前就跑完了。关于异步方法、回调方法、入参方法的运行顺序我们可以通过一个小例子来验证一下。参考https://www.jianshu.com/p/1c829edec185
let a = new Promise( function(resolve, reject) { console.log(1) //同步方法 setTimeout(() => console.log(2), 0) //回调方法 console.log(3) //同步方法 console.log(4) //同步方法 resolve(true) //异步方法 } ) a.then(v => { console.log(8) }) let b = new Promise( function() { console.log(5) //同步方法 setTimeout(() => console.log(6), 0) //回调方法 } ) console.log(7) //同步方法
我们可看到输出结果为1、3、4、5、7、8、2、6。从这里我们发现异步方法优先于回调方法执行。
从这里我们可以总结出,使用promise异步编程时一定要小心与回调方法混合使用,先理清楚再决定调用方法的顺序
参考https://www.jianshu.com/p/1c829edec185
参考https://blog.csdn.net/u010297791/article/details/71158212