предисловие
Друзья, которые занимаются фронтендом, контактировали более-менееPromise
, когда в коде слишком много уровней функций обратного вызова, вы обнаружитеPromise
Очарование асинхронного программирования, я думаю, эта статья поможет вам решить ваши проблемы.
Концепция обещания
Promise
даJS
Важная концепция асинхронного программирования, асинхронная абстрактная обработка объектов, в настоящее время более популярна.Javascript
Одно из решений асинхронного программирования
Возможно, у автора ограниченные способности к восприятию и он не питает благосклонности к официальной терминологии, поясню простым языком:
Promise
объект с тремя состояниями (pending
,fulfilled
,rejected
), который может связывать асинхронные запросы (then
метод) и хорошо обрабатывать исключения,
Это одно из хороших решений для устранения ада обратного вызова.
Функция обратного вызова, обрабатывающая многоуровневый асинхронный пример
$.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 API
'new' 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.prototype.then
Promise#then
promise.then(onFulfilled, onRejected)
вернуть новыйpromise
Здесь часто возникает вопрос: почему бы не вернуться к исходномуpromise
, люди так думают, если возвращают одно и то жеpromise
Состояние несовместимо, и в спецификации промиса указано, что когдаpending
кfulfilled
/ rejected
После того, как статус определен, его нельзя изменить.
Promise.prototype.catch
Promise#catch
promise.catch(function(error){ throw new Error(error); })
Уведомление:IE8
и ниже появятся версииidentifier not found
синтаксическая ошибка, вы можете изменить запись через точку на запись в квадратных скобках
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.prototype.finally
promise.finally(onFinally)
вернутьPromise
,существуетpromise
В конце выполнения, каким бы ни был результатfulfilled
илиrejected
, выполнениеthen()
а такжеcatch()
После этого будет выполняться
Promise.all
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
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 polyfill & Test
promise-polyfill.js
Учусь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;
promise-aplus-tests
Потому что это ссылка (копия) тест (копия) предшественниковpolyfill
, есть две ошибки при самостоятельном написании теста,ES6 Promise
нормативный2.3.1
а также2.3.4
2.3.1
2.3.4
Исправлено и успешно протестировано
постскриптум
Ваша поддержка - моя самая большая мотивация. Нелегко ложиться спать допоздна и кодировать слова. Если эта статья была вам полезна, пожалуйста, не стесняйтесьstar
:GitHub.com/Чен Помфрет…
Студенты, которые заинтересованы в добавлении друзей к автору, отсканируйте приведенный ниже QR-код (1. Мой WeChat, 2. Публичная учетная запись WeChat, 3. Группа WeChat по обмену технологиями), и я хотел бы подружиться с вами, чтобы обсудить технологии и болтать о жизни!