JavaScript Promise迷你书(中文版)读书笔记
JavaScript Promise迷你书(中文版)
promise chain
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | function taskA() {     console.log("Task A"); } function taskB() {     console.log("Task B"); } function onRejected(error) {     console.log("Catch Error: A or B", error); } function finalTask() {     console.log("Final Task"); }
  var promise = Promise.resolve(); promise     .then(taskA)     .then(taskB)     .catch(onRejected)     .then(finalTask);
  | 
 
上面代码中的promise chain的执行流程,如果用一张图来描述一下的话,像下面的图那样。

Figure 3. promise-then-catch-flow.js附图
在 上述代码 中,我们没有为 then 方法指定第二个参数(onRejected),也可以像下面这样来理解。
then
注册onFulfilled时的回调函数
catch
注册onRejected时的回调函数
再看一下 上面的流程图 的话,我们会发现 Task A 和 Task B 都有指向 onRejected 的线出来。
这些线的意思是在 Task A 或 Task B 的处理中,在下面的情况下就会调用 onRejected 方法。
发生异常的时候
返回了一个Rejected状态的promise对象
在 第一章 中我们已经看到,Promise中的处理习惯上都会采用 try-catch 的风格,当发生异常的时候,会被 catch 捕获并被由在此函数注册的回调函数进行错误处理。
另一种异常处理策略是通过 返回一个Rejected状态的promise对象 来实现的,这种方法不通过使用 throw 就能在promise chain中对 onRejected 进行调用。
关于这种方法由于和本小节关系不大就不在这里详述了,大家可以参考一下第4章 使用reject而不是throw 中的内容。
此外在promise chain中,由于在 onRejected 和 Final Task 后面没有 catch 处理了,因此在这两个Task中如果出现异常的话将不会被捕获,这点需要注意一下。
下面我们再来看一个具体的关于 Task A → onRejected 的例子。
Task A产生异常的例子
Task A 处理中发生异常的话,会按照TaskA → onRejected → FinalTask 这个流程来进行处理。

Figure 4. Task A产生异常时的示意图
将上面流程写成代码的话如下所示。
promise-then-taska-throw.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   | function taskA() {     console.log("Task A");     throw new Error("throw Error @ Task A") } function taskB() {     console.log("Task B"); } function onRejected(error) {     console.log(error); } function finalTask() {     console.log("Final Task"); }
  var promise = Promise.resolve(); promise     .then(taskA)     .then(taskB)     .catch(onRejected)     .then(finalTask);
  | 
 
执行这段代码我们会发现 Task B 是不会被调用的。
在本例中我们在taskA中使用了 throw 方法故意制造了一个异常。但在实际中想主动进行onRejected调用的时候,应该返回一个Rejected状态的promise对象。关于这种两种方法的异同,请参考 使用reject而不是throw 中的讲解。
promise和操作方法(通过超时取消XHR操作)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
   | "use strict"; var requestMap = {}; function createXHRPromise(URL) {     var req = new XMLHttpRequest();     var promise = new Promise(function (resolve, reject) {         req.open('GET', URL, true);         req.onreadystatechange = function () {             if (req.readyState === XMLHttpRequest.DONE) {                 delete requestMap[URL];             }         };         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.onabort = function () {             reject(new Error('abort this req'));         };         req.send();     });     requestMap[URL] = {         promise: promise,         request: req     };     return promise; }
  function abortPromise(promise) {     if (typeof promise === "undefined") {         return;     }     var request;     Object.keys(requestMap).some(function (URL) {         if (requestMap[URL].promise === promise) {             request = requestMap[URL].request;             return true;         }     });     if (request != null && request.readyState !== XMLHttpRequest.UNSENT) {         request.abort();     } } module.exports.createXHRPromise = createXHRPromise; module.exports.abortPromise = abortPromise;
   | 
 
定义进行顺序处理的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
   | function sequenceTasks(tasks) {     function recordValue(results, value) {         results.push(value);         return results;     }     var pushValue = recordValue.bind(null, []);     return tasks.reduce(function (promise, task) {         return promise.then(task).then(pushValue);     }, Promise.resolve()); } 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 sequenceTasks([request.comment, request.people]); }
  main().then(function (value) {     console.log(value); }).catch(function(error){     console.error(error); });
  |