Promise
未处理的 Error
在浏览器中,我们可以使用 unhandledrejection 事件捕获它:
window.addEventListener('unhandledrejection', function(event) {// the event object has two special properties:alert(event.promise); // [object Promise] - the promise that generated the erroralert(event.reason); // Error: Whoops! - the unhandled error object});new Promise(function() {throw new Error("Whoops!");}); // no catch to handle the error
“error-first callback” 风格
loadScript('/my/script.js', function(error, script) {if (error) {// handle error} else {// 成功加载脚本}});function loadScript(src, callback) {let script = document.createElement('script');script.src = src;script.onload = () => callback(null, script);script.onerror = () => callback(new Error(`Script load error for ${src}`));document.head.append(script);}
promise 对象有内部属性:
state—— 最初是 “pending”,然后被改为 “fulfilled” 或 “rejected”,result—— 一个任意值,最初是undefined。
reject/throw a error
从技术上来说,我们可以使用任何类型的参数来调用 reject(就像 resolve)。但建议在 reject(或从它们中继承)中使用 Error 对象。 错误原因就会显示出来。
Promise chain
因为 promise.then 返回了一个 promise,所以我们可以用它调用下一个 .then。
当控制函数返回一个值时,它会变成当前 promise 的 result,所以会用它调用下一个 .then
new Promise(function(resolve, reject) {setTimeout(() => resolve(1), 1000); // (*)}).then(function(result) { // (**)alert(result); // 1return result * 2;}).then(function(result) { // (***)alert(result); // 2return result * 2;}).then(function(result) {alert(result); // 4return result * 2;});
返回thenable对象
.then 可以返回任意的 “thenable” 对象,并且会被当做一个 promise 来对待
class Thenable {constructor(num) {this.num = num;}then(resolve, reject) {alert(resolve); // function() { native code }// 1 秒后用 this.num*2 来 resolvesetTimeout(() => resolve(this.num * 2), 1000); // (**)}}new Promise(resolve => resolve(1)).then(result => {return new Thenable(result); // (*)}).then(alert); // 1000 ms 后显示 2
then方法中返回 promises 允许我们建立异步动作链。
错误处理
当一个 promise reject 时,代码控制流程跳到链中最近的 rejection 处理程序。这在实践中非常方便。
隐式catch
new Promise(function(resolve, reject) {throw new Error("Whoops!");}).catch(alert); // Error: Whoops!=== 等于下面的new Promise(function(resolve, reject) {reject(new Error("Whoops!"));}).catch(alert); // Error: Whoops!
re-throw
如果我们在 .catch 里面 throw,那么控制流程将转到下一个最接近的错误处理程序。
如果我们处理错误并正常结束,那么它将继续执行最接近的 .then 成功处理程序。
Promise.resolve
根据给定的 value 值返回 resolved promise。
等价于:
let promise = new Promise(resolve => resolve(value));
如何接口的一致性 可以使用loadCached(url).then这样子
确保接口返回都返回Promise
function loadCached(url) {let cache = loadCached.cache || (loadCached.cache = new Map());if (cache.has(url)) {return Promise.resolve(cache.get(url)); // (*)}return fetch(url).then(response => response.text()).then(text => {cache[url] = text;return text;});}
Promise.all
下面的 Promise.all 在 3 秒之后被处理,然后它的结果就是一个 [1, 2, 3] 数组
Promise.all([new Promise((resolve, reject) => setTimeout(() => resolve(1), 3000)), // 1new Promise((resolve, reject) => setTimeout(() => resolve(2), 2000)), // 2new Promise((resolve, reject) => setTimeout(() => resolve(3), 1000)) // 3]).then(alert);
如果任何 promise 为 rejected,Promise.all 就会立即以 error reject。
如何避免fetch请求中一个错误导致Promise.all失败
根据 promise 的工作原理,只要 .then/catch 处理器返回值(无论是 error 对象或其他内容),执行流程就会“正常”进行
Promise.all(urls.map(url => fetch(url).catch(err => err)))
await-to-js - 优雅的try-catch
await-to-js
https://www.npmjs.com/package/await-to-js
import to from 'await-to-js';// If you use CommonJS (i.e NodeJS environment), it should be:// const to = require('await-to-js').default;async function asyncTaskWithCb(cb) {let err, user, savedTask, notification;[ err, user ] = await to(UserModel.findById(1));if(!user) return cb('No user found');[ err, savedTask ] = await to(TaskModel({userId: user.id, name: 'Demo Task'}));if(err) return cb('Error occurred while saving task');if(user.notificationsEnabled) {[ err ] = await to(NotificationService.sendNotification(user.id, 'Task Created'));if(err) return cb('Error while sending notification');}if(savedTask.assignedUser.id !== user.id) {[ err, notification ] = await to(NotificationService.sendNotification(savedTask.assignedUser.id, 'Task was created for you'));if(err) return cb('Error while sending notification');}cb(null, savedTask);}
