В повседневной работе фронтальной работы функция обратного вызова не должна не удивлена, но когда функция обратного вызова столкнулась с ASYNC (ASYNC), это возмутительно. Так что же означает асинхронный? Проще говоря, это означает, что код ниже будет выполнен, прежде чем закончить его выполнение.
Например 🌰:
Наша наиболее часто используемая асинхронная операция должна быть ajax (я думаю, что когда я впервые использовал ajax, это была катастрофа. Очевидно, что ресурс был успешно загружен, почему данные не передаются в ресурс? Это действительно раздражает.) можно только дождаться завершения загрузки, а затем выполнить соответствующие операции для достижения успеха. Таким образом, весь код, который мы видим, должен выглядеть так.
/**
@param callback 回调函数
*/
function getData(url,callback){
$.ajax({
url:url,
success:function(result){
callback(result);
}
});
}
//假设我有好多个ajax,每个ajax都需要上一个ajax的支持,于是……地狱出现了……
getData(url1,function(res){
getData(url2,function(res){
getData(url3,function(res){
//终于可以干正事了
})
})
})
Друзья, поймите callback hell.
Итак, обещание появилось, и его появление решило ад обратных вызовов! Он инкапсулирует асинхронные функции и превращает обратные вызовы в связанные вызовы.
Например 🌰:
function getData(url){
return new Promise((resolve,reject)=>{
$.ajax({
url:url,
success:function(result){
resolve(result);
},
error:function(error){
reject(error);
}
});
})
}
getData(url1).then(function(res){
return getData(url2)
}).then(function(res){
return getData(url3)
}).then(function(res){
//干正事啦!
})
В самом деле. Это намного проще, по крайней мере, скобки на трех внутренних слоях и трех внешних слоях не спутают.
Но когда я услышал обетование, я отверг его в своем сердце. Хоть я и отказываюсь в сердце своем, но то, что должно прийти, все равно должно прийти, а тому, чему следует научиться, еще предстоит научиться, ведь время идет, а идти в ногу со временем еще надо! Так как же выполняется это обещание? ? ?
Реализация 1: Статус
Друзья, обещайте здесь не романтическую строчку «Обещаю ХХХ» в знакомствах между мужчинами и женщинами, а норму.Щелкните здесь, чтобы ознакомиться со спецификациями. Однако обещание здесь, как и обещание в реальной жизни, имеет три состояния: выполнено, отклонено и ожидает исполнения.
Например 🌰:
Предположим, Мэри и Майк - пара.Полгода назад Майк пообещал Мэри завершить их свадьбу в течение полугода, но Майк до сих пор не предпринял никаких действий, поэтому Мэри сказала, что не будет заставлять ждать (в ожидании), поэтому Они распались, то обещание было отклонено. Если Майк и Мэри поженятся в течение шести месяцев, Майк уже должен был выполнить свое обещание, данное Мэри.
Итак, у всех промисов есть состояние результата — выполнено или отклонено, и состояние перед результатом — ожидание.
//p1.js
function Promise(executor){
let _=this;
_.value=undefined;
_.reason=undefined;
_.state="pending"//大家一开始都是一样,等着吧
function resolve(value){
_.value=value//实现之后的感言
_.state="fulfilled"//实现啦!
}
function reject(reason){
_.reason=reason //给我一个被拒绝的理由
_.state="rejected" //被拒绝了!
}
executor(resolve,reject)
}
//e.g
let Iagree=new Promise((resolve,reject)=>{
resolve("我开心就同意了");//
})
let Idisagree=new Promise((resolve,reject)=>{
reject("我不开心就拒绝了");
})
let noResult=new Promise((resolve,reject)=>{
})
console.log(Iagree.state,Idisagree.state,noResult.state)
Реализация 2: добавьте функцию then
Но я знаю только, что толку от одного состояния? Я должен перейти к следующему шагу! нам нужноthen
, для следующего шага.
//p2.js
Promise.prototype.then=function(onFulfilled, onRejected){
let _=this;
if(_.state=="pending"){}
if(_.state=="fulfilled"){
onFulfilled(_.value)
}
if(_.state=="rejected"){
onRejected(_.reason)
}
}
//e.g
let Iagree=new Promise((resolve,reject)=>{
resolve("我开心就同意了");//强行完成(fullfilled)
})
Iagree.then((data)=>{
console.log(Iagree.state)
},(e)=>{
console.log(e)
})
Реализация 3: реализовать асинхронное выполнение
Однако это делается одновременно, а не асинхронно. Давайте посмотрим на асинхронность ~
В это время нам нужно передать функцию обратного вызова в разрешение или отклонение, но что, если у нас есть много последующих методов? потом сколько раз делать! Бросьте callback в очередь, и тогда Foreach будет выполняться один за другим.
//p3.js
function Promise(executor){
//....
_.resolveCallbacks=[];//callbacks在pending中添加,fullfilled中执行
_.rejectCallbacks=[];//callbacks在pending中添加,rejected中执行
function resolve(value){
//....
_.resolveCallbacks.forEach((fn)=>fn())
}
function reject(reason){
//....
_.rejectCallbacks.forEach((fn)=>fn())
}
//....
}
Promise.prototype.then=function(onFulfilled, onRejected){
let _=this;
if(_.state=="pending"){
//把回调方法塞进队列中
_.resolveCallbacks.push(()=>{
onFulfilled(_.value)
})
_.rejectCallbacks.push(()=>{
onRejected(_.reason)
})
}
//....
}
//e.g
let Iagree=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("我开心就同意了");
},1000)
})
//为了防止多次then,所以回调方法需要丢入队列中,防止方法被覆盖。
Iagree.then((data)=>{
console.log(Iagree.state)
},(e)=>{
console.log(e)
})
Iagree.then((data)=>{
console.log(Iagree.state+1)
},(e)=>{
console.log(e)
})
Реализация 4: реализация цепочек вызовов
Так что вопрос в том, если я прямо тогда, я могу? Так:
Iagree.then((data)=>{
...
}).then((data)=>{
...
}).then((data)=>{
...
})
Если вы хотите написать так, то предыдущий шагthen
Вы должны вернуть объект обещания, в противном случае вы можете изменить егоthen
метод. Поэтому нам нужноthen
серединаnew
новое обещание для следующего связанного вызоваthen
.
//p4.js
function resolvePromise(promise,x,resolve,reject){
//如果x可能是一个promise
if(x!==null&&(typeof x==="object"||typeof x==="function")){
let then=x.then;
//如果x是一个promise,因为promise都要有then函数的
if(typeof then === "function"){
//y表示x这个promise的值
then.call(x,y=>{
//继续遍历,直至返回值不是promise
resolvePromise(promise,y,resolve,reject)
},err=>{
reject(err)
})
}else{
//如果x是个普通对象,直接运行
resolve(x)
}
}else{
//如果x不是一个promise,也就是x是一个常量,直接运行
resolve(x)
}
}
Promise.prototype.then=function(onFulfilled, onRejected){
let _=this;
let promise2;
//将当前promise的值传递到下一次then的调用中
function resolveFunction(promise,resolve,reject){
let x=onFulfilled(_.value)
resolvePromise(promise,x,resolve,reject)
}
function rejectFunction(promise,resolve,reject){
let x=onRejected(_.reason)
resolvePromise(promise,x,resolve,reject)
}
promise2=new Promise((resolve,reject)=>{
if(_.state=="pending"){
//把回调方法塞进队列中
_.resolveCallbacks.push(()=>{
resolveFunction(promise2,resolve,reject)
})
_.rejectCallbacks.push(()=>{
rejectFunction(promise2,resolve,reject)
})
}
if(_.state=="fulfilled"){
resolveFunction(promise2,resolve,reject)
}
if(_.state=="rejected"){
rejectFunction(promise2,resolve,reject)
}
})
return promise2
}
//e.g
let Iagree=new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("我开心就同意了");
},1000)
})
//为了防止多次then,所以回调方法需要丢入队列中,防止方法被覆盖。
Iagree.then((data)=>{
console.log(data)
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("看心情干活");
},1000)
})
}).then((data)=>{
console.log("前方返回一个promise:"+data)
return data+",我是一个常量"
}).then((data)=>{
console.log("常量返回:"+data)
}).then((data)=>{
console.log("前方无法返回:"+data)
})
Таким образом, мы можем счастливо связывать промисы, о чем приятно подумать. Однако вышеописанное — это всего лишь простой и грубый способ реализации промисов, всего лишь принцип, и некоторые спецификации промисов нуждаются в доработке.Щелкните здесь, чтобы ознакомиться со спецификациями.
Соответствует спецификации promisesA+
Обобщить несколько пунктов
- Должен
try{}catch(){}
Все места отмечены, я скорее убью по ошибке, чем отпущу. - Методы onFulfilled и onRejected помещаются в
setTimeout
В том числе, чтобы превратить их в «макрозадачи». (Это должно быть сделано из соображений производительности и будет изучено позже.) - затем добавьте
Promise.defer = Promise.deferred = function(){}
метод предотвращения несанкционированного доступа. - Затем экспортируйте обещание,
module.exports=Promise
. - Последний прогон
promises-aplus-tests.cmd 你的promise.js
, затем пройдите свой код построчно, подождите, пока все не станет зеленым (прохождение), поздравляем с успешным завоеванием промиса! !
//参考p5.js