Promise基础用法(下)|青训营笔记

73 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的的第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高级程序设计》,希望能够让自己写的代码更精简美观。

参考笔记:前端 | JS Promise:axios 请求结果后面的 .then() 是什么意思?