从事前端的朋友或多或少的接触过Promise
,当代码中回调函数层级过多你就会发现Promise
异步编程的魅力,相信此文必定能帮你排忧解惑
前端
Promise
是JS
异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript
异步编程解决方案之一 或许是笔者理解能力有限,对官方术语怎么也感觉不到亲切,下面我来用通俗易懂的语言解释下: git
Promise
是一个包含三种状态的对象(pending
、fulfilled
、rejected
),能够链式的处理异步请求(then
方法)并能很好地处理异常问题, 是解决回调地狱的良好方案之一。 github
回调函数处理多层异步示例
ajax
$.ajax({
url: url1,
success: function(rsp){
$.ajax({
url: url2,
success: function(rsp){
$.ajax({
url: url3,
success: function(rsp){
//do sth
},
error: function(error){
}
});
},
error: function(error){
}
});
},
error: function(error){
}
});
复制代码
将promise
封装在$.ajax
中
编程
$.ajax = function(config){
return new Promise(function(resolve, reject){
//1省略...
xmlhttp.onreadystatechange = function(){
if(xmlhttp.status==200){
resolve(rspData);
}else{
reject(xmlhttp.statusText);
}
};
//2省略...
})
}
$.ajax({url: url1}).then(function(val){
return $.ajax({url: val.url})
}).then(function(val){
return $.ajax({url: val.url})
}).catch(function(err){
console.log(err);
}}
复制代码
封装好的Promise
处理异步可读性可维护性以及代码美观度不言而喻
promise
//pending状态的promise
var promise = new Promise(function(resolve, reject){
//do sth
})
//fulfilled状态的promise
var promise = Promise.resolve(1)
.then(function resolve(value){console.log(value)});
// var promise = new Promise(function(resolve){resolve(1)})
//rejected状态的promise
var promise = Promise.reject(new Error('error'))
.catch(function(error){console.error(error)});
// var promise = new Promise(function(resolve,reject){resolve(new Error('error'))})
复制代码
Promise#then
promise.then(onFulfilled, onRejected)
复制代码
返回一个新的promise
这里常常会有一个疑问:为何不返回原来的promise
,我的是这样认为的,若返回同一个promise
则状态不一致,promise规范说明当pending
至fulfilled
/ rejected
时状态肯定后不能再改变。
浏览器
Promise#catch
promise.catch(function(error){ throw new Error(error); })
复制代码
注意:IE8
及如下版本会出现 identifier not found
的语法错误,可将点标记法改成中括号标记法
bash
promise['catch'](function(error){
throw new Error(error);
})
复制代码
rejected
状态的promise
抛出异常,至关于
微信
promise.then(undefined, onRejected)
复制代码
then & catch
结合示例
异步
promise.then(function f1(value){
//do sth 1
}).then(function f2(value){
//do sth 2
}).then(function f3(value){
//do sth 3
}).catch(function(error){
console.log(error);
})
复制代码
promise.finally(onFinally)
复制代码
返回一个Promise
,在promise
执行结束时,不管结果是fulfilled
或者是rejected
,在执行then()
和catch()
后,都会执行
promise.all([promise1, promise2, promise3]).then(resolve);
复制代码
示例
// `delay`毫秒后执行resolve
function timerPromisefy(delay) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(delay);
}, delay);
});
}
var startDate = Date.now();
// 全部promise变为resolve后程序退出
Promise.all([
timerPromisefy(1),
timerPromisefy(32),
timerPromisefy(64),
timerPromisefy(128)
]).then(function (values) {
console.log(Date.now() - startDate + 'ms');
// 约128ms
console.log(values); // [1,32,64,128]
});
复制代码
在接收到全部的对象promise
都变为 FulFilled
返回一个resolve(array);
或者 某一个promise
对象变成Rejected
状态返回resolve(err)
传递给 Promise.all
的promise
并非一个个的顺序执行的,而是同时开始、并行执行的
promise.race([promise1, promise2]).then(resolve, reject)
复制代码
示例
// `delay`毫秒后执行resolve
function timerPromisefy(delay) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(delay);
}, delay);
});
}
// 任何一个promise变为resolve或reject 的话程序就中止运行
Promise.race([
timerPromisefy(1),
timerPromisefy(32),
timerPromisefy(64),
timerPromisefy(128)
]).then(function (value) {
console.log(value); // => 1
});
复制代码
只要有一个promise
对象进入 FulFilled
或者 Rejected
状态的话,就会继续进行后面的处理。
学习完Promise
后,一定要重写Promise
,后续遇到浏览器环境不支持也可有的放矢 代码以下
/**
* @author chenchangyuan
* @date 2019-02-23
* */
function Promise(executor){
if(typeof executor !== 'function'){
throw new Error('executor is not a function');
}
var self = this;
self.state = 'pending';//pending fulfilled rejected
self.value = null;
self.reason = null;
self.callbackResolveFn = [];
self.callbackRejectFn = [];
function resolve(value){
if(self.state === 'pending'){
self.state = 'fulfilled';
self.value = value;
self.callbackResolveFn.forEach(function(fn){
fn();
});
}
}
function reject(reason){
if(self.state === 'pending'){
self.state = 'rejected';
self.reason = reason;
self.callbackRejectFn.forEach(function(fn){
fn();
});
}
}
try{
executor(resolve, reject);
}catch(err){
reject(err);
}
}
//回溯函数
function resolvePromise(promise, x, resolve, reject){
if(promise === x) return reject(new TypeError('循环引用'));
var flag = false;
if(x !== null && (typeof x === 'object' || typeof x === 'function')){
try{
var then = x.then;
if(typeof then === 'function'){
then.call(x, function(val){
if(flag) return;
flag = true;
resolvePromise(promise, val, resolve, reject);
}, function(err){
if(flag) return;
flag = true;
reject(err);
});
}else{
resolve(x);
}
} catch(err){
if(flag) return;
flag = true;
reject(err);
}
}else{
resolve(x);
}
}
//返回一个新的promise(pending:push(fn),fulfilled:resolve(val),rejected:reject(reason))
Promise.prototype.then = function(onFulfilled, onRejected){
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(value){
return value;
};
onRejected = typeof onRejected === 'function' ? onRejected : function(err){
throw new Error(err);
};
var self = this,
promise2;
if(self.state === 'fulfilled'){
promise2 = new Promise(function(resolve, reject){
setTimeout(function(){
try{
//将x处理成一个原始值
var x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch(e){
reject(e);
}
})
})
}
if(self.state === 'rejected'){
promise2 = new Promise(function(resolve, reject){
setTimeout(function(){
try{
//将x处理成一个原始值
var x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch(e){
reject(e);
}
})
})
}
if(self.state === 'pending'){
promise2 = new Promise(function(resolve, reject){
self.callbackResolveFn.push(function(){
setTimeout(function(){
try{
//将x处理成一个原始值
var x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch(e){
reject(e);
}
})
});
self.callbackRejectFn.push(function(){
setTimeout(function(){
try{
//将x处理成一个原始值
var x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch(e){
reject(e);
}
})
});
})
}
return promise2;
}
Promise.prototype['catch']= function (callback) {
return this.then(undefined, callback)
}
Promise.all = function (promises) {
return new Promise(function (resolve, reject) {
let arr = [];
let i = 0;
function processData(index, y) {
arr[index] = y;
if (++i === promises.length) {
resolve(arr);
}
}
for (let i = 0; i < promises.length; i++) {
promises[i].then(function (y) {
processData(i, y)
}, reject)
}
})
}
Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
for (var i = 0; i < promises.length; i++) {
promises[i].then(resolve,reject)
}
});
}
Promise.resolve = function(value){
return new Promise(function(resolve,reject){
resolve(value);
});
}
Promise.reject = function(reason){
return new Promise(function(resolve,reject){
reject(reason);
});
}
Promise.defer = Promise.deferred = function () {
var d = {};
d.promise = new Promise(function (resolve, reject) {
d.resolve = resolve;
d.reject = reject;
});
return d
}
module.exports = Promise;复制代码
因为是参(抄)考(袭)前辈的polyfill
,本身编码测试时出现了两处错误,ES6 Promise
规范的2.3.1
和2.3.4
2.3.1
2.3.4
通过改正测试成功
大家的支持是我最大的动力,熬夜码字不易,若是此文对你有帮助,请不吝star
:github.com/chenchangyu…
有兴趣加笔者好友的同窗请扫描下方二维码(1.本人微信,2.微信公众号,3.技术交流微信群),愿与您成为好友共同探讨技术,畅聊生活!