Promise方法 理解 封装

 Promise是什么?

Promise直接打印出来看看吧,console.dir(Promise),就这么简单粗暴

Promise方法 理解 封装_第1张图片

可以看出:Promise是一个构造函数。ES6中新增的。 

从打印的结果可以看出 里面有 all race reject resolve 等方法  原型上有 catch  constructor  finally  then方法

作用:为了解决异步代码的编程问题。将代码的书写风格,从回调套回调,变为从上到下。

从上到下执行的方式 减少了回调套回调的书写

这里注意一下因为Promise同步方法 所以我们使用的时候的应该把它放在函数中执行

// 定义第一个任务
let username  = function() {
    return new Promise(function(resolve, reject) {
      
    });
}

Promise的构造函数接收一个参数,是函数,并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数。其实这里用“成功”和“失败”来描述并不准确,按照标准来讲,resolve是将Promise的状态置为fullfiled,reject是将Promise的状态置为rejected。不过在我们开始阶段可以先这么理解,后面再细究概念。

案例:

// 初始化一个Promise实例
let  username  = new Promise(function(resolve, reject) {
    resolve:函数,当执行的时候会将p的状态变为resolved
    reject:函数,当执行的时候会将p的状态变为rejected
});

此时,我们将Promise的参数中的resolve执行:

let p = new Promise(function(resolve, reject) {
    resolve();
});   
console.log(p);

此时,p的状态变为了: fulfilled 也就是resolved

再重新将reject执行:

let p = new Promise(function(resolve, reject) {
    // resolve();
});   
console.log(p);

此时,p的状态变为了rejected 并且还报错了。

报错的原因:因为没有设置resolved时的处理函数。

总结:

Promise接收一个函数作为参数,通常会在该函数体内发送异步请求。并在异步请求结束之后,调用resolve或者reject。

此时Promise实例的状态也会随之变化。

处理函数

then  当Promise的状态发生变化,进行后续的逻辑上的代码处理

当Promise的状态发生变化的时候,我们应当进行后续的逻辑上的代码处理。

“成功时,怎么办?失败时,怎么办?”

Promise的实例上有一个then方法,就是用来处理这个问题的。

promise.then(successCallback, failCallback);

successCallback: 当状态变为resolved时,执行的回调函数

failCallback: 当状态变为rejected时,执行的回调函数

注:promise实例的状态通常跟异步请求的执行结果挂钩

第一种情况:

                             异步请求成功 => resolve()

                             异步请求失败 => reject()

但是也可以第二种情况:

                                 异步请求成功 => reject()

                                  异步请求失败 => resolve()

但是没人会执行第二种情况

处理异步的方式

let p = new Promise(function(resolve, reject) {
    // 异步调用
    setTimeout(function() {
        resolve();
        // reject();
    }, 3000);
});    
p.then(function() {
    console.log("成功了"); 
}, function() {
    console.log("失败了");
});

成功时,也就是resolve()

失败时,也就是reject()

如果不执行resolve也不执行reject,则永远不会执行任何代码。

总结:
Promise实例的状态:
只可能
		pending => resolved/fulfilled  
或
pending => rejected 
一旦确定状态,则不可能逆向,也不可能改变。

resolve  rejected 传递参数

代码是从异步的回调中抽离到p.then方法的参数函数中了。

但是作用域也变了。从参数函数中,根据作用域是无法得到异步请求回来的数据的。

 

当reslove rejected函数执行的时候可以传递一个参数。而且仅此一个。 

let p = new Promise(function(resolve, reject) {
    // 发送异步请求
    $.ajax({
        url: "/ajax1",
        dataType: "json",
        success: function(data) {
            // 判定返回的json数据中的错误代码来决定本次的请求成功还是失败
            if (!data.error) {
                // 成功
                resolve(1, 2, 3, 4, 5);
                
                // 刻意调用失败
                 //reject("a", "b", "c", "d");
            } else {
                // 失败
                reject();
            }
        }
    });
});

// 监听状态变化
p.then(function(data) {
    console.log(arguments);
    // 当前作用域下能够访问的数据 包含自身作用域中定义的内容和全局作用域中的内容
    // 访问不到success回调函数中的数据
    // 答:作用域已经无法帮助我们获取数据,但是传递参数可以。 
    // 当reslove函数执行的时候可以传递一个参数。而且仅此一个。
    console.log("成功");

}, function(data) {
    console.log(data)
    console.log("失败");
});

then的连续调用与传递参数   单个Promise实例

当针对一个Promise的实例绑定多组处理函数时,只有第一组处理函数,会根据Promise实例的状态而发生变化,后面的每一组,只有第一个函数会执行。

连续调用:

我们可以针对一个Promise实例调用多次then方法。绑定多个处理函数。

let p = new Promise(function(resolve, reject) {
    $.ajax({
        url: "/ajax1",
        dataType: "json",
        success: function(data) {
            // 成功
            // resolve("A");
            // 失败
            reject("B");
        }
    })
});

// 监听p的状态变化
p.then(function(data) {
    console.log("成功1处理函数", data);
}, function(data) {
    console.log("失败1处理函数", data);
})
.then(function(data) {
    console.log("成功2处理函数", data);
}, function(data) {
    console.log("失败2处理函数", data);
})
.then(function(data) {
    console.log("成功3处理函数", data);
}, function(data) {
    console.log("失败3处理函数", data);
})

此时,只有第一个处理函数会接收到reject传递的参数: 后面的每一个处理函数都没有接收到数据

处理方法

后面的函数想要获取参数,必须由前一个函数返回

let p = new Promise(function(resolve, reject) {
    $.ajax({
        url: "/ajax1",
        dataType: "json",
        success: function(data) {
            // 成功
            // resolve("A");
            // 失败
            reject("B");
        }
    })
});

// 监听p的状态变化
p.then(function(data) {
    console.log("成功1处理函数", data);
}, function(data) {
    console.log("失败1处理函数", data);  // B 这个是reject传递的
    return "C";
})
.then(function(data) {
    console.log("成功2处理函数", data); // C 这个是前一个处理函数的返回值
    return "D";
}, function(data) {
    console.log("失败2处理函数", data);
})
.then(function(data) {
    console.log("成功3处理函数", data);  // D 这个是前一个处理函数的返回值
}, function(data) {
    console.log("失败3处理函数", data);
})

总结:

当针对一个Promise实例进行多个函数的处理时,第一个函数的参数,是resolve或者reject传递的。

后续的函数中的参数,是由前一个处理函数的return决定的。

 

then的连续调用与传递参数   多个Promise实例  catch  (重点)

// 定义一个Promise实例
function task1() {
    return new Promise(function(resolve, reject) {
        $.get("/ajax1", function(data) {
            // 根据返回结果 决定调用resolve reject
            resolve();
        }, "json");
    });
}
function task2() {
    return new Promise(function(resolve, reject) {
        $.get("/ajax2", function(data) {

            // 根据返回结果 决定调用resolve reject
            reject("second");

        }, "json");
    });
}


// 初始化第一个任务
let p = task1();


// 监听第一个任务
p.then(function() {
    // 第一个成功
    console.log("第一个成功");
    return task2();
})
.then(function() {
    // 第二个成功
    console.log("第二个成功");
})
.catch(function(data) {
    console.log("失败了", data);
});
console.log("执行到底");

 catch  无法处理Promise之外的代码中的异常  throw

function task1() {

    throw new Error("123");  // 这里不属于Promise

    return new Promise(function(resolve, reject) {
        $.get("/ajax1", function(data) {
            resolve("第一个成功");
        }, "json");
    });
}
function task2() {
    return new Promise(function(resolve, reject) {
        $.get("/ajax2", function(data) {
            // 根据返回结果 决定调用resolve reject
            reject("第二个失败");
        }, "json");
    });
}
// 初始化第一个任务
let p = task1();
// 监听第一个任务
p.then(function() {
    // 第一个成功
    console.log("第一个成功");
    return task2();
})
.then(function() {
    // 第二个成功
    console.log("第二个成功");
})
.catch(function(data) {
    console.log("失败了", data);
});
console.log("执行到底");

  catch 处理属于Promise的同步代码中的异常

function task1() {
    return new Promise(function(resolve, reject) {
        throw new Error("123");  // 这里属于Promise 也是同步代码
        $.get("/ajax1", function(data) {
            resolve("第一个成功");
        }, "json");
    });
}

Promise方法 理解 封装_第2张图片

  catch 无法处理属于Promise的异步代码

function task1() {
    return new Promise(function(resolve, reject) {
        $.get("/ajax1", function(data) {
            throw new Error("123");  // 这里虽然属于Promise范围内,但是是回调函数中。属于异步,所以catch无法处理
            resolve("第一个成功");
        }, "json");
    });
}

Promise方法 理解 封装_第3张图片

 finally   常用来测试

function task1() {
    return new Promise(function(resolve, reject) {
        $.get("/ajax1", function(data) {
            // resolve("第一个成功");
            reject("第一个失败");
        }, "json");
    });
}
function task2() {
    return new Promise(function(resolve, reject) {
        $.get("/ajax2", function(data) {
            // 根据返回结果 决定调用resolve reject
            resolve("第二个成功");
        }, "json");
    });
}
// 初始化第一个任务
let p = task1();
// 监听第一个任务
p.then(function() {
    // 第一个成功
    console.log("第一个成功");
    return task2();
})
.then(function() {
    // 第二个成功
    console.log("第二个成功");
})
.catch(function(data) {
    console.log("失败了", data);
    console.log("虽然失败了,但是还是执行到我了");
})
.finally(function() {
    console.log("最终还是执行了我", arguments);
});
console.log("执行到底");

Promise的静态方法     Promise.all    Promise.race

Promise.all

该方法用于同时监听多个Promise实例。返回一个新的Promise实例。当被监听的每一个Promise实例都状态变为resolved时,会将返回值的新Promise实例的状态变为resolved。当任何一个被监听的Promise实例状态变为rejected时,就会执行返回值的失败处理函数。

function task1() {

    throw new Error("123");  // 这里不属于Promise

    return new Promise(function(resolve, reject) {
        $.get("/ajax1", function(data) {
            resolve("第一个成功");
        }, "json");
    });
}

function task2() {
    return new Promise(function(resolve, reject) {
        $.get("/ajax2", function(data) {
            // 根据返回结果 决定调用resolve reject
            reject("第二个失败");
        }, "json");
    });
}


let p = Promise.all([task1(), task2()]);

p.then(function(arr) {

    console.log("成功", arr);  
    // arr是一个数组 分别是task1() 和task2状态变为resolved时传递的数据 位置一一对应
})
.catch(function(data) {
    console.log("失败", data); 
    // data是一个信息 是状态变为rejected的那一个Promise在调用  reject时,传递的参数
});

Promise方法 理解 封装_第4张图片

Promise.race 

Promise.race也是用于监听多个Promise实例。

Promise.all 返回的实例只有在所有的被监听的Promise实例都resolved之后,才会resolved。

Promise.race返回的实例只监听第一个返回的Promise实例的状态变化。

被监听了3个Promise实例。

如果其中某任何一个第一个发生状态的变化,Promise.race的返回值也会相应的发生变化。

简而言之:只监听第一个返回的Promise实例。

Promise.race(arr);

arr: 数组 数组中的每一个成员都是Promise实例。如果不是,会使用Promise.resolve转为Promise实例。但是此时,一定是监听它。

返回值:新的Promise实例

function task1() {

    throw new Error("123");  // 这里不属于Promise

    return new Promise(function(resolve, reject) {
        $.get("/ajax1", function(data) {
            resolve("第一个成功");
        }, "json");
    });
}

function task2() {
    return new Promise(function(resolve, reject) {
        $.get("/ajax2", function(data) {
            // 根据返回结果 决定调用resolve reject
            reject("第二个失败");
        }, "json");
    });
}


let p = Promise.race([task1(), task2()]);

p.then(function(data) {
    console.log(data);
})
.catch(function(data) {
    console.log(data);
});

Promise方法 理解 封装_第5张图片

thenable对象

所谓的thenable对象指的是普通对象具备then方法

let p = Promise.resolve({
    then: function(resolve, reject) {
        setTimeout(function() {
            // resolve("1");
            reject("2");
        }, 3000)
    }
});  // 红色的对象具备then方法,所以是一个thenable对象
// 等价于
let p = new Promise(function(resolve, reject) {
    setTimeout(function() {
        // resolve("1");
        reject("2");
    }, 3000)
});  // 蓝色的部分其实就是红色对象的then方法

promise封装

var Promise = (function() {
    function Promise(resolver) {
        if (typeof resolver !== 'function') { //resolver必须是函数
            throw new TypeError('Promise resolver ' + resolver + ' is not a function')
        }
        if (!(this instanceof Promise)) return new Promise(resolver)

        var self = this //保存this
        self.callbacks = [] //保存onResolve和onReject函数集合
        self.status = 'pending' //当前状态

        function resolve(value) {
            setTimeout(function() { //异步调用
                if (self.status !== 'pending') {
                    return
                }
                self.status = 'resolved' //修改状态
                self.data = value

                for (var i = 0; i < self.callbacks.length; i++) {
                    self.callbacks[i].onResolved(value)
                }
            })
        }

        function reject(reason) {
            setTimeout(function(){ //异步调用
                if (self.status !== 'pending') {
                    return
                }
                self.status = 'rejected' //修改状态
                self.data = reason

                for (var i = 0; i < self.callbacks.length; i++) {
                    self.callbacks[i].onRejected(reason)
                }
            })
        }

        try{
            resolver(resolve, reject) //执行resolver函数
        } catch(e) {
            reject(e)
        }
    }

    function resolvePromise(promise, x, resolve, reject) {
        var then
        var thenCalledOrThrow = false

        if (promise === x) {
            return reject(new TypeError('Chaining cycle detected for promise!'))
        }

        if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {
            try {
                then = x.then
                if (typeof then === 'function') {
                    then.call(x, function rs(y) {
                        if (thenCalledOrThrow) return
                        thenCalledOrThrow = true
                        return resolvePromise(promise, y, resolve, reject)
                    }, function rj(r) {
                        if (thenCalledOrThrow) return
                        thenCalledOrThrow = true
                        return reject(r)
                    })
                } else {
                    return resolve(x)
                }
            } catch(e) {
                if (thenCalledOrThrow) return
                thenCalledOrThrow = true
                return reject(e)
            }
        } else {
            return resolve(x)
        }
    }

    Promise.prototype.then = function(onResolved, onRejected) {
        //健壮性处理,处理点击穿透
        onResolved = typeof onResolved === 'function' ? onResolved : function(v){return v}
        onRejected = typeof onRejected === 'function' ? onRejected : function(r){throw r}
        var self = this
        var promise2

        //promise状态为resolved
        if (self.status === 'resolved') {
            return promise2 = new Promise(function(resolve, reject) {
                setTimeout(function() {
                    try {
                        //调用then方法的onResolved回调
                        var x = onResolved(self.data)
                        //根据x的值修改promise2的状态
                        resolvePromise(promise2, x, resolve, reject)
                    } catch(e) {
                        //promise2状态变为rejected
                        return reject(e)
                    }
                })
            })
        }

        //promise状态为rejected
        if (self.status === 'rejected') {
            return promise2 = new Promise(function(resolve, reject) {
                setTimeout(function() {
                    try {
                        //调用then方法的onReject回调
                        var x = onRejected(self.data)
                        //根据x的值修改promise2的状态
                        resolvePromise(promise2, x, resolve, reject)
                    } catch(e) {
                        //promise2状态变为rejected
                        return reject(e)
                    }
                })
            })
        }

        //promise状态为pending
        //需要等待promise的状态改变
        if (self.status === 'pending') {
            return promise2 = new Promise(function(resolve, reject) {
                self.callbacks.push({
                    onResolved: function(value) {
                        try {
                            //调用then方法的onResolved回调
                            var x = onResolved(value)
                            //根据x的值修改promise2的状态
                            resolvePromise(promise2, x, resolve, reject)
                        } catch(e) {
                            //promise2状态变为rejected
                            return reject(e)
                        }
                    },
                    onRejected: function(reason) {
                        try {
                            //调用then方法的onResolved回调
                            var x = onRejected(reason)
                            //根据x的值修改promise2的状态
                            resolvePromise(promise2, x, resolve, reject)
                        } catch(e) {
                            //promise2状态变为rejected
                            return reject(e)
                        }
                    }
                })
            })
        }
    }

    //获取当前Promise传递的值
    Promise.prototype.valueOf = function() {
        return this.data
    }

    //由then方法实现catch方法
    Promise.prototype.catch = function(onRejected) {
        return this.then(null, onRejected)
    }

    //finally方法
    Promise.prototype.finally = function(fn) {
        return this.then(function(v){
            setTimeout(fn)
            return v
        }, function(r){
            setTimeout(fn)
            throw r
        })
    }

    Promise.prototype.spread = function(fn, onRejected) {
        return this.then(function(values) {
            return fn.apply(null, values)
        }, onRejected)
    }

    Promise.prototype.inject = function(fn, onRejected) {
        return this.then(function(v) {
            return fn.apply(null, fn.toString().match(/\((.*?)\)/)[1].split(',').map(function(key){
                return v[key];
            }))
        }, onRejected)
    }

    Promise.prototype.delay = function(duration) {
        return this.then(function(value) {
            return new Promise(function(resolve, reject) {
                setTimeout(function() {
                    resolve(value)
                }, duration)
            })
        }, function(reason) {
            return new Promise(function(resolve, reject) {
                setTimeout(function() {
                    reject(reason)
                }, duration)
            })
        })
    }

    Promise.all = function(promises) {
        return new Promise(function(resolve, reject) {
            var resolvedCounter = 0
            var promiseNum = promises.length
            var resolvedValues = new Array(promiseNum)
            for (var i = 0; i < promiseNum; i++) {
                (function(i) {
                    Promise.resolve(promises[i]).then(function(value) {
                        resolvedCounter++
                        resolvedValues[i] = value
                        if (resolvedCounter == promiseNum) {
                            return resolve(resolvedValues)
                        }
                    }, function(reason) {
                        return reject(reason)
                    })
                })(i)
            }
        })
    }

    Promise.race = function(promises) {
        return new Promise(function(resolve, reject) {
            for (var i = 0; i < promises.length; i++) {
                Promise.resolve(promises[i]).then(function(value) {
                    return resolve(value)
                }, function(reason) {
                    return reject(reason)
                })
            }
        })
    }

    Promise.resolve = function(value) {
        var promise = new Promise(function(resolve, reject) {
            resolvePromise(promise, value, resolve, reject)
        })
        return promise
    }

    Promise.reject = function(reason) {
        return new Promise(function(resolve, reject) {
            reject(reason)
        })
    }

    Promise.fcall = function(fn){
        // 虽然fn可以接收到上一层then里传来的参数,但是其实是undefined,所以跟没有是一样的,因为resolve没参数啊
        return Promise.resolve().then(fn)
    }

    Promise.done = Promise.stop = function(){
        return new Promise(function(){})
    }

    Promise.deferred = Promise.defer = function() {
        var dfd = {}
        dfd.promise = new Promise(function(resolve, reject) {
            dfd.resolve = resolve
            dfd.reject = reject
        })
        return dfd
    }

    try { // CommonJS compliance
        module.exports = Promise
    } catch(e) {}

    return Promise
})()

Promise方法 理解 封装_第6张图片

你可能感兴趣的:(ES6,promise)