js 语言的特性, 造就了特别的异步处理方式, 我记得以前用的最多的就是回调函数, 那个时候写 jquery 的 ajax 时候, 特别喜欢写这种代码:
- $.ajax({
- method:get,
- url:"http://text/api",
- success:function(){
- $.ajax({
- method:get,
- url:"http://text/api",
- success:function(){}
- });
- }
- });
后一个 ajax 的发送需要依赖前面的 ajax 的返回, 也许有的朋友说还好啊, 其实一两个确实还好, 但是多了就比较晕不直观后面调试起来有点麻烦后来很多浏览器就自己实现了一种 promise 原生对象, 这个对象提供一系列方法, 来解决这种回调带来的不直观, 不易维护的问题
首先, 这个 promise 很多浏览器已经实现了, 开发者只需要调用就可以, 就像 window,document 之类的一样首先介绍一下它的用法吧!
我们需要通过 new 调用 Promise 对象, 这个对象需要传入一个函数, 函数有两个参数, 分别是 resolve,reject, 分别代表成功和失败两种状态, 同时还有一个 then 的方法, 它也有两函数作为参数, 第一个表示任务处理成功的后续操作, 第二个表示任务处理失败的后续操作, 当我们调用实例上的 then 的方法后, promise 会根据我们在 new Promise 过程中调用的是 resolve 还是 reject 来判断应该执行哪一个函数
这样我们可以简单粗暴的改写一个上面那个 ajax 的代码
这样一来代码变的更加明了, 而且 then 方法可以一直链式调用下去, 不管有多少异步任务都可以通过 then 方法写下去
接下来, 我们看看怎么模拟这种操作, 写一个自己的 promise
首先, 我们需要设定三种状态, 成功, 失败 和 等待, 也就是一个任务完成的情况, 做完了就是成功, 没做好就是失败, 还没开始做就是等待
这就完成了一个 promise 最基本的功能, 此时, 如果在 excutor 函数中, 出现一个异步任务, 需要等待一秒才能执行 resolve 或者 reject, 此时状态会处于 pending, 我们需要做一个数组, 把这些等着状态的任务装起来, 在 reject 或者 resolve 执行时候, 遍历数组, 一个一个依次执行
接下来增加链式调用功能
到此我们还要解决用户在 then 方法中随意返回数据的问题, 用户可能返回一个普通值, 也可能返回一个新的 promise, 因此还需要作进一步处理
- function Promise(executor) { // executor 是一个执行函数
- let self = this;
- self.status = pending;
- self.value = undefined; // 默认成功的值
- self.reason = undefined; // 默认失败的原因
- self.onResolvedCallbacks = []; // 存放 then 成功的回调
- self.onRejectedCallbacks = []; // 存放 then 失败的回调
- function resolve(value) { // 成功状态
- if (self.status === pending) {
- self.status = resolved;
- self.value = value;
- self.onResolvedCallbacks.forEach(function(fn) {
- fn();
- });
- }
- }
- function reject(reason) { // 失败状态
- if (self.status === pending) {
- self.status = rejected;
- self.reason = reason;
- self.onRejectedCallbacks.forEach(function(fn) {
- fn();
- })
- }
- }
- try {
- executor(resolve, reject)
- } catch(e) { // 捕获的时候发生异常, 就直接失败了
- reject(e);
- }
- }
- function resolvePromise(p2, x, resolve, reject) {
- // 有可能这里返回的 x 是别人的 promise
- // 尽可能允许其他乱写
- if (p2 === x) { // 这里应该报一个类型错误, 有问题
- return reject(new TypeError(循环引用了))
- }
- // 看 x 是不是一个 promise,promise 应该是一个对象
- if (x !== null || (typeof x === object || typeof x ===
- function)) {
- // 可能是 promise {}, 看这个对象中是否有 then 方法, 如果有 then 我就认为他是 promise 了
- try { // {then:1}
- let then = x.then;
- if (typeof then ===
- function) {
- // 成功
- then.call(x,
- function(y) {
- // y 可能还是一个 promise, 在去解析直到返回的是一个普通值
- resolvePromise(promise2, y, resolve, reject)
- },
- function(err) { // 失败
- reject(err);
- })
- } else {
- resolve(x)
- }
- } catch(e) {
- reject(e);
- }
- } else { // 说明是一个普通值 1
- resolve(x); // 表示成功了
- }
- }
- Promise.prototype.then = function(onFulfilled, onRjected) {
- let self = this;
- let promise2; // 返回的 promise
- if (self.status === resolved) {
- promise2 = new Promise(function(resolve, reject) {
- // 当成功或者失败执行时有异常那么返回的 promise 应该处于失败状态
- // x 可能是一个 promise 也有可能是一个普通的值
- let x = onFulfilled(self.value);
- // x 可能是别人 promise, 写一个方法统一处理
- resolvePromise(promise2, x, resolve, reject);
- })
- }
- if (self.status === rejected) {
- promise2 = new Promise(function(resolve, reject) {
- let x = onRjected(self.reason);
- resolvePromise(promise2, x, resolve, reject);
- })
- }
- // 当调用 then 时可能没成功 也没失败
- if (self.status === pending) {
- promise2 = new Promise(function(resolve, reject) {
- // 此时没有 resolve 也没有 reject
- self.onResolvedCallbacks.push(function() {
- let x = onFulfilled(self.value);
- resolvePromise(promise2, x, resolve, reject);
- });
- self.onRejectedCallbacks.push(function() {
- let x = onRjected(self.reason);
- resolvePromise(promise2, x, resolve, reject);
- });
- })
- }
- return promise2;
- }
- // mjs
module.exports = Promise 到此基本完成 promise 的基本功能, 但还有一些方法没有实现, 比如 race,
all,
也没有实现同时调用 reject 和 resolve 的问题, 后续有时间再处理有问题请指正
来源: http://www.bubuko.com/infodetail-2527657.html