这是我参与「第四届青训营 」笔记创作活动的的第16天. 在和小伙伴讨论的过程中发现JavaScript高级语法中promise的使用是个难点,于是在此记录一下目前对promise的浅显的理解,此为下篇。
使用 Promise:链式调用
如果只是用 then 来绑定回调函数,那并不能解决回调地狱的问题。然而很妙的地方来了: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);
链式调用的实现[#]
能做到链式调用的魔法来自 then() 方法:它会在执行相应的回调函数之后,返回一个新的 Promise 对象,并且插入 Promise 链的当前位置。
这里稍微有点绕,容易把回调函数等同于 then() 方法本身。实际上成功/失败的回调函数只是 then() 的参数而已;而实际执行 then() 的时候,它会先根据 promise 的状态调用相应的回调函数,再根据回调函数的执行结果生成一个新的 Promise 对象并返回;具体的对应规则如下:
| 回调函数执行情况 | then() 返回的 Promise 对象 |
|---|---|
返回值 return x; | fulfilled 状态,参数为 x |
直接返回 return; / 无 return 语句 | fulfilled 状态,参数为 undefined |
抛出错误 throw err; | rejected 状态,参数为 err |
| 返回已决议的 Promise | 状态和参数与返回的 Promise 一致 |
| 返回未定的 Promise | 未定的 Promise,回调参数与返回的相同 |
下面这个例子中,初始 Promise 的状态为已拒绝,然后第一个 then() 调用了绑定的 onRejected,返回了状态为 fulfilled 的新 Promise 对象,并传递给了链中的下一个 then():
Promise.reject()
.then(() => 99, () => 42) // 调用 onRejected(return 42;),表格中的第一种情况
.then(solution => console.log('Resolved with ' + solution)); // Resolved with 42
同时,你可能还记得 then() 的参数定义,两个回调函数都是可选的;如果没有传入对应的回调函数,then() 会直接把原 promise 的终态返回,不做额外处理。
创建 Promise 对象
如果要执行的异步操作没有返回 Promise 对象,可以用 new 和构造器创建自己的 promise。构造器的两个参数的作用是在异步操作成功/失败时,转换 Promise 对象的状态并传递对应参数。
const myFirstPromise = new Promise((resolve, reject) => {
// 做一些异步操作,最终会调用下面两者之一:
// resolve(someValue); // fulfilled
// reject("failure reason"); // rejected
});
// 一个例子
function myAsyncFunction(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = () => resolve(xhr.responseText);
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
});
};
感想
promise的异步操作涵盖了JavaScript精华知识点,关于面向对象和回调,要继续精进前端开发的技术,需要继续进修JavaScript高级语法。笔者目前除了参加青训营的课程外,还在研读前端红宝书——《JavaScript高级程序设计》,希望能够让自己写的代码更精简美观。