本篇文章通过构建一个简单的Promise对象来了解如何做到异步获得数据。
const fetch = function(url) { return new Promise((resolve, reject) => { request((error, apiResponse) => { if (error) { //返回为error的时候,调用reject函数 reject(error) } // 有数据返回的时候,调用resolve resolve(apiResponse) }) }) }
这个fetch()的方法返回了一个Promise对象,接着我们就可以用then来对获得的数据进行处理,catch来捕获可能的错误。
首先,我们要知道Promise实际上是一个对象,当我们运行下面的代码可以发现返回true。
console.log(typeof new Promise((resolve, reject) => {}) === 'object') // true
接着要构建一个Promise类,来生成Promise Object。
在constructor 里面传入executionFunction, 然后将onResolve,onReject映射到里面,then主要做一件事情,就是将onResolve的函数收集起来,在this.onResolve里面一起调用,每次返回的值都覆盖前一次的。
说的什么玩意儿,眼见为实下面来看一下代码:
class PromiseSimple{ constructor(executionFunction) { this.promiseChain = []; this.onResolve = this.onResolve.bind(this) this.onReject = this.onReject.bind(this) this.handleError = () => {} // 外界传入的函数我们将其定义为executionFunction,将里面 // 的onResolve onReject 映射到this.onResolve, this.onReject executionFunction(this.onResolve, this.onReject) } then(onResolve) { // 收集状态成功的时候的回调函数 this.promiseChain.push(onResolve) return this } catch(onReject) { this.handleError = onReject return this } onResolve(value) { var storedValue = value; try { // 在resolve里面执行 this.promiseChain.forEach((executePromise) => { storedValue = executePromise(storedValue) }) } catch(error){ this.promiseChain = []; this.onReject(error) } } onReject(error) { this.handleError(error) } }
1、这个对象有四个方法then catch onResolve onReject,它们的作用分别是
用来收集有数据的时候的回调函数,放在this.promiseChain里,注意这里要返回this 对象才能实现链式调用
用来处理出现的error,注意这里要返回this对象实现链式调用
依次执行then里面收集的回调函数,并且将回调函数的返回值在作为参数传给下一个回调函数
用来处理出现的error
2、then catch 必须要返回this,才能实现链式调用
这样我们一个简单的Promise 对象就做好了
下面可以用这个来玩一玩
class PromiseSimple { constructor(executionFunction) { this.promiseChain = []; this.handleError = () => {}; this.onResolve = this.onResolve.bind(this); this.onReject = this.onReject.bind(this); executionFunction(this.onResolve, this.onReject); } then(onResolve) { this.promiseChain.push(onResolve); return this; } catch(handleError) { this.handleError = handleError; return this; } onResolve(value) { let storedValue = value; try { this.promiseChain.forEach((nextFunction) => { storedValue = nextFunction(storedValue); }); } catch (error) { this.promiseChain = []; this.onReject(error); } } onReject(error) { this.handleError(error); } } fakeApiBackend = () => { const user = { username: 'treyhuffine', favoriteNumber: 42, profile: 'https://gitconnected.com/treyhuffine' }; // Introduce a randomizer to simulate the // the probability of encountering an error if (Math.random() > .05) { return user; } else { const error = { statusCode: 404, message: 'Could not find user', error: 'Not Found', }; return error; } }; // Assume this is your AJAX library. Almost all newer // ones return a Promise Object const makeApiCall = () => { return new PromiseSimple((resolve, reject) => { // Use a timeout to simulate the network delay waiting for the response. // This is THE reason you use a promise. It waits for the API to respond // and after received, it executes code in the `then()` blocks in order. // If it executed is immediately, there would be no data. setTimeout(() => { const apiResponse = fakeApiBackend(); if (apiResponse instanceof Error) { reject(apiResponse); } else { resolve(apiResponse); } }, 5000); }); }; makeApiCall() .then((user) => { console.log('In the first .then()'); return user; }) .then((user) => { console.log(`User ${user.username}'s favorite number is ${user.favoriteNumber}`); return user; }) .then((user) => { console.log('The previous .then() told you the favoriteNumber') return user.profile; }) .then((profile) => { console.log(`The profile URL is ${profile}`); }) .then(() => { console.log('This is the last then()'); }) .catch((error) => { console.log(error.message); });
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句