Promise快速上手
一、回调地狱
在没有Promise之前,如果我们想要操作多个异步函数,会有回调地狱
doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log('Got the final result: ' + finalResult); }, failureCallback); }, failureCallback); }, failureCallback);
同时这种写法还有另外两个问题:
- 回调函数命名缺乏规范, 每个程序员都有可能给回调函数起不同的名字
- 不能很好地捕获错误
二、初探Promise
Promise可以完美解决以上三个问题,即
- 解决回调地狱,增强代码可读性
- 规范回调的名字或顺序
- 很方便地捕获错误
而有了Promise后, 相同的操作可以写成:
doSomething().then(function(result) { return doSomethingElse(result); }) .then(function(newResult) { return doThirdThing(newResult); }) .then(function(finalResult) { console.log('Got the final result: ' + finalResult); }) .catch(failureCallback);
以上的回调函数还可以简化为箭头函数
doSomething() .then(result => doSomethingElse(result)) .then(newResult => doThirdThing(newResult)) .then(finalResult => { console.log(`Got the final result: ${finalResult}`); }) .catch(failureCallback);
三、怎么写一个Promise
promise对象是由window.Promise构造函数得到的一个对象
从0开始新建一个promise对象:
Promise
对象是由关键字 new
及其构造函数来创建的。该构造函数接受两个函数——resolve
和 reject
——作为其参数。当异步任务顺利完成且返回结果值时,会调用 resolve
函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject
函数。
resolve函数和reject函数都只接受一个参数
const myFirstPromise = new Promise((resolve, reject) => { // ?做一些异步操作,最终会调用下面两者之一: // // resolve(someValue); // fulfilled // ?或 // reject("failure reason"); // rejected });
想让一个函数有Promise对象的功能:
return new Promose( (resolve, reject) => { )
function myAsyncFunction(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.onload = () => resolve(xhr.responseText); // 成功就调用resolve函数 xhr.onerror = () => reject(xhr.statusText); // 失败就调用reject函数 xhr.send(); }); };
基础示例
let myFirstPromise = new Promise(function(resolve, reject){ //当异步代码执行成功时,我们才会调用resolve(...), 当异步代码失败时就会调用reject(...) //在本例中,我们使用setTimeout(...)来模拟异步代码,实际编码时可能是XHR请求或是HTML5的一些API方法. setTimeout(function(){ resolve("成功!"); //代码正常执行! }, 250); }); myFirstPromise.then(function(successMessage){ //successMessage的值是上面调用resolve(...)方法传入的值. //successMessage参数不一定非要是字符串类型,这里只是举个例子 console.log("Yay! " + successMessage); }, function(errorMessage){ // reject会调用这个函数 });
易混淆点:resolve 和 reject 和 then(succes, fail)
new Promise(function(resolve, reject){}里的resolve 和 reject 并不是 .then(succes, fail) 里面的 success 和 fail,
resolve 会去调用 success,reject 会去调用 fail
AJAX+Promise请求图片示例
源码地址:https://github.com/mdn/js-examples/blob/master/promises-test/index.html
function imgLoad(url) { // Create new promise with the Promise() constructor; // This has as its argument a function // with two parameters, resolve and reject return new Promise(function(resolve, reject) { // Standard XHR to load an image let request = new XMLHttpRequest(); request.open('GET', url); request.responseType = 'blob'; // When the request loads, check whether it was successful request.onload = function() { if (request.status === 200) { // If successful, resolve the promise by passing back the request response resolve.call(null, request.response); } else { // If it fails, reject the promise with a error message reject.call(null, Error('Image didn\'t load successfully; error code:' + request.statusText)); } }; request.onerror = function() { // Also deal with the case when the entire request fails to begin with // This is probably a network error, so reject the promise with an appropriate message reject.call(null, Error('There was a network error.')); }; // Send the request request.send(); }); } // Get a reference to the body element, and create a new image object var body = document.querySelector('body'); var myImage = new Image(); // Call the function with the URL we want to load, but then chain the // promise then() method on to the end of it. This contains two callbacks imgLoad('myLittleVader.jpg').then(function(response) { // The first runs when the promise resolves, with the request.response // specified within the resolve() method. var imageURL = window.URL.createObjectURL(response); myImage.src = imageURL; body.appendChild(myImage); // The second runs when the promise // is rejected, and logs the Error specified with the reject() method. }, function(Error) { console.log(Error); });
四、Promise使用方法小结
第一步
- return new Promise((resolve, reject) =>{...})
- 任务成功就调用 resolve.call(null, result)
- 任务失败就调用 reject.call(null, errorMessage)
- resolve和reject会再去调用成功和失败函数
第二步
- 使用.then(success, fail) 传入成功和失败函数
a. success.call(null, result) 参数来自resolve
b.fail.call(null, errorMessage) 参数来自reject