Atualmente, um grande número de operações assíncronas está envolvido na demanda, e as páginas reais estão cada vez mais inclinadas a aplicações de uma página única. No futuro, você pode usar estrutura de backbone, angular, nocaute e outras, mas o problema da programação assíncrona é o primeiro problema a ser enfrentado. Com a ascensão dos nós, a programação assíncrona se tornou um tópico muito quente. Após um período de aprendizado e prática, alguns detalhes da programação assíncrona estão resumidos.
1. Classificação da programação assíncrona
Os métodos para resolver o problema assíncrono geralmente incluem: retorno de chamada direto, pub/sub -modo (modo de evento), biblioteca de controle de biblioteca assíncrona (como async, quando), promessa, gerador etc.
1.1 Função de retorno de chamada
As funções de retorno de chamada são comumente usadas para resolver soluções assíncronas, muitas vezes expostas e usadas, fáceis de entender e muito fáceis de implementar em bibliotecas ou funções. Esse também é um método que as pessoas costumam usar ao usar programação assíncrona.
No entanto, o método da função de retorno de chamada tem os seguintes problemas:
1. Uma pirâmide do mal aninhada pode ser formada e o código não é fácil de ler;
2. Apenas uma função de retorno de chamada pode ser correspondente, que se torna um limite em muitos cenários.
1.2 pub/sub -modo (evento)
Esse padrão também é chamado de modo de evento, que é a eventização das funções de retorno de chamada e é muito comum em bibliotecas de classes como o jQuery.
O próprio modo de assinante de publicação do evento não tem o problema de chamadas síncronas e assíncronas, mas no nó, as chamadas emitem são desencadeadas principalmente assíncronas com o loop do evento. Esse modo é frequentemente usado para dissociar a lógica de negócios. Os editores de eventos não precisam prestar atenção à função de retorno de chamada registrado, nem precisam prestar atenção ao número de funções de retorno de chamada. Os dados podem ser transmitidos de maneira flexível através de mensagens.
Os benefícios desse padrão são: 1. Fácil de entender; 2. Não é mais limitado a uma função de retorno de chamada.
Quando se trata de coisas ruins: 1. Você precisa usar a biblioteca de classes; 2. A ordem dos eventos e funções de retorno de chamada é muito importante
A cópia do código é a seguinte:
var iMg = document.QuerySelect (#Id);
img.addeventListener ('load', function () {
// A imagem é carregada
......
});
img.addeventListener ('erro', function () {
// algo deu errado
......
});
Existem dois problemas com o código acima:
um. O IMG foi realmente carregado e a função de retorno de chamada de carga está ligada neste momento. Como resultado, o retorno de chamada não será executado, mas ainda espera executar a função de retorno de chamada correspondente.
A cópia do código é a seguinte:
var iMg = document.QuerySelect (#Id);
função load () {
...
}
if (img.complete) {
carregar();
} outro {
img.addeventListener ('carregamento', carga);
}
img.addeventListener ('erro', function () {
// algo deu errado
......
});
b. Incapaz de lidar bem com exceções
Conclusão: O mecanismo de eventos é mais adequado para lidar com eventos repetidos no mesmo objeto, e não há necessidade de considerar o evento antes que a função de retorno de chamada seja vinculada.
1.3 Biblioteca de controle assíncrona
As bibliotecas assíncronas atuais incluem principalmente q, quando.js, win.js, rsvp.js, etc.
A característica dessas bibliotecas é que o código é linear e pode ser escrito de cima para baixo, de acordo com os hábitos naturais.
As coisas ruins também são diferentes em estilos, que são inconvenientes de ler e aumentar os custos de aprendizagem.
1.4 Promessa
A promessa é traduzida para o chinês como uma promessa. Pessoalmente, após a conclusão assíncrona, ele dará um resultado externo (sucesso ou falha) e prometerá que o resultado não mudará mais. Em outras palavras, a Promise reflete o valor final do resultado de retorno de uma operação (uma promessa representa o valor eventual retornado da conclusão única de uma operação). Atualmente, a promessa foi introduzida na especificação ES6, e navegadores avançados como Chrome e Firefox implementaram esse método nativo internamente, o que é bastante conveniente de usar.
A seguir, são apresentadas as características da promessa dos seguintes aspectos:
1.4.1 Status
Ele contém três estados: pendente, cumprido e rejeitado. Os três estados só podem passar por duas transições (de pendente ---> cumpridas, pendentes-> rejeitadas), e a transição do estado só pode ocorrer apenas uma vez.
1.4.2 Então, método
O método então é usado para especificar a função de retorno de chamada após a conclusão do evento assíncrono.
Pode -se dizer que esse método é o método de promessa da alma, que faz promessa cheia de magia. Existem várias manifestações específicas da seguinte forma:
a) Então o método retorna promessa. Isso permite operações em série de várias operações assíncronas.
Em relação ao círculo amarelo 1 na figura acima, o processamento do valor é uma parte mais complicada da promessa. O processamento do valor é dividido em duas situações: promessa objeto e objeto não promessa.
Quando o valor não for um tipo de promessa, basta usar o valor como o valor do parâmetro da resolução da segunda promessa; Quando é um tipo de promessa, o status e os parâmetros do Promise2 são completamente determinados pelo valor. Pode -se considerar que o Promsie2 é um fantoche de valor, e o Promise2 é apenas uma ponte que conecta o assíncrono diferente.
A cópia do código é a seguinte:
Promise.Prototype.Then = function (onfulfilled, onrejected) {
retornar nova promessa (função (resolver, rejeitar) {// A promessa aqui é marcada como Promise2
lidar({
Onfulfilled: Onfulfilled,
on -rejeitado: onrejeded,
Resolva: Resolva,
Rejeite: rejeitar
})
});
}
identificador de função (diferido) {
var handlefn;
if (estado === 'cumprido') {
handlefn = adiado.onfulfilled;
} else if (estado === 'rejeitado') {
handlefn = adiado.onRejeded;
}
var ret = handlefn (valor);
adido.Resolve (RET); // Observe que a resolução neste momento é a resolução de promessa2
}
função resolve (val) {
if (val && typeof val.Then === 'function') {
val.hen (resolve); // Se Val é um objeto de promessa ou um objeto de promessa de classe, o estado de promessa2 é completamente determinado por Val
retornar;
}
if (retorno de chamada) {// retorno de chamada é a função de retorno de chamada especificada
retorno de chamada (Val);
}
}
b) A conversão entre múltiplas bibliotecas assíncronas diferentes é implementada.
Existe um objeto chamado que é capaz de assíncrono, que se refere a um objeto com o método então. Enquanto um objeto tiver o método então, ele pode ser convertido, por exemplo:
A cópia do código é a seguinte:
var diferred = $ ('aa.ajax'); // !! adido.then === true
var p = Promise.Resolve (diferido);
p. then (......)
1.4.3 Commonjs Promise/A Specification
Atualmente, existem especificações Promise/A e Promise/A+ para as especificações sobre a promessa, o que mostra que a implementação da promessa é bastante complicada.
A cópia do código é a seguinte:
Então (FulFiledHandler, rejeitoundler, ProgressHandler)
1.4.4 Notas
A função de retorno de chamada em uma promessa compartilha o valor. No processamento do resultado, o valor é passado como um parâmetro para a função de retorno de chamada correspondente. Se o valor for um objeto, tenha cuidado para não modificar facilmente o valor.
A cópia do código é a seguinte:
var p = promeso.Resolve ({x: 1});
p.hen (função (val) {
console.log ('primeiro retorno de chamada:'+val.x ++);
});
p.hen (função (val) {
console.log ('Segundo retorno de chamada:' + val.x)
})
// Primeiro retorno de chamada: 1
// Segundo retorno de chamada: 2
1.5 gerador
Todos os métodos acima são baseados na função de retorno de chamada para concluir operações assíncronas e nada mais são do que encapsular a função de retorno de chamada. O ES6 propõe o gerador, que adiciona maneiras de resolver operações assíncronas e não é mais concluído com base nas funções de retorno de chamada.
A maior característica do gerador é que ele pode pausar e reiniciar as funções, que são muito propícias a resolver operações assíncronas. Combinar a pausa do gerador com o manuseio de exceções da Promise pode resolver o problema de programação assíncrona com mais elegância. Referência de implementação específica: Kyle Simpson
2. Problemas com programação assíncrona
2.1 Manuseio de exceção
a) Eventos assíncronos incluem dois links: emitindo solicitações assíncronas e resultados de processamento. Esses dois links são conectados através de loops de eventos. Então, ao tentar o Catch para executar a captura de exceção, você precisa capturá -la.
A cópia do código é a seguinte:
tentar {
assíncada (retorno de chamada);
} catch (err) {
......
}
O código acima não pode capturar a exceção no retorno de chamada e só pode obter a exceção no processo de solicitação. Isso tem problemas: se a emissão de solicitação e o processamento da solicitação forem concluídos por duas pessoas, há problemas ao lidar com exceções?
b) Promova implementa a entrega de exceção, o que traz alguns benefícios para garantir que o código não esteja bloqueado em projetos reais. No entanto, se houver muitos eventos assíncronos, não é fácil descobrir qual evento assíncrono produz uma exceção.
A cópia do código é a seguinte:
// Descrição da cena: Exiba as informações de alarme de preço no CRM, incluindo informações competitivas. No entanto, leva muito tempo para obter as informações competitivas. Para evitar a consulta lenta, o back -end divide um recorde em duas peças para obtê -lo separadamente.
// Etapa 1: Obtenha informações de alarme de preço, além das informações da concorrência
função getPriCealarmData () {
Retorne nova promessa (função (resolve) {
Y.io (url, {
Método: 'Get',
Dados: params,
on: function () {
Sucesso: function (id, dados) {
resolver (alarmData);
}
}
});
});
}
// Depois de obter as informações do alarme, vá para obter as informações da concorrência
getPRICEALArMDATA (). Então (função (dados) {
// renderização de dados, além de informações competitivas
renderizar (dados);
Retorne nova promessa (função (resolve) {
Y.io (url, {
Método: 'Get',
Dados: {alarmList: dados},
on: function () {
Sucesso: function (id, compdata) {
resolver (compdata);
}
}
});
});
}) // Depois de obter todos os dados, a renderização das informações da concorrência
.Then (function (dados) {
// renderizar as informações de licitação
renderizar (dados)
}, function (err) {
// Manuseio de exceção
console.log (err);
});
O código acima pode ser convertido para o seguinte:
A cópia do código é a seguinte:
tentar{
// Obtenha informações de alarme além da concorrência
var alarmData = alarmDataExceptCompare ();
renderizar (alarmdata);
// Inquérito de informações sobre concorrência com base em informações de alarme
var com comparação = getCompareInfo (alarmData);
renderizar (comparado aTATA);
} catch (err) {
console.log (err.message);
}
No exemplo acima, a exceção é tratada no final, de modo que, quando ocorre uma exceção em um determinado link, não podemos saber exatamente qual evento é gerado.
2.2 JQuery.Deferred Problem
As operações assíncronas também são implementadas no jQuery, mas não cumprem as especificações Promise/A+ na implementação e são refletidas principalmente nos seguintes aspectos:
um. Número de parâmetros: a promessa padrão pode aceitar apenas um parâmetro, enquanto o jQuery pode passar vários parâmetros
A cópia do código é a seguinte:
função asyncinjQuery () {
var d = novo $ .Deferred ();
setTimeout (function () {
d.Resolve (1, 2);
}, 100);
Retornar d.promise ()
}
asyncinjQquery (). Então (função (val1, val2) {
console.log ('saída:', val1, val2);
});
// saída: 1 2
b. Manuseio de exceções no processamento de resultados
A cópia do código é a seguinte:
função asyncinpromise () {
Retorne nova promessa (função (resolve) {
setTimeout (function () {
var jSonstr = '{"name": "mt}';
resolver (JSonstr);
}, 100);
});
}
asyncinpromise (). Então (função (val) {
var d = json.parse (val);
console.log (D.Name);
}). Então (nulo, function (err) {
console.log ('Mostrar erro:' + err.message);
});
// Mostrar erro: final inesperado de entrada
função asyncinjQuery () {
var d = novo $ .Deferred ();
setTimeout (function () {
var jSonstr = '{"name": "mt}';
D.Resolve (JSonstr);
}, 100);
Retornar d.promise ()
}
asyncinJQuery (). Então (função (val) {
var d = json.parse (val);
console.log (D.Name);
}). Então (função (v) {
console.log ('sucesso:', v.name);
}, function (err) {
console.log ('Mostrar erro:' + err.message);
});
// SyntaxError não capturado: Fim inesperado de entrada
Pode ser visto a partir disso que promessa processa o resultado da função de retorno de chamada, que pode capturar exceções durante a execução da função de retorno de chamada, mas o jQuery.Deferred não pode.