Domanda

Recentemente lavoro su un nuovo progetto e questo progetto utilizza callback javascript in nodejs.Ora usiamo koa ma il problema accade quando proviamo a utilizzare generatori ES6 e callbacks.

//Calback function
function load(callback){
  result = null;
  //Do something with xmla4js and ajax
  callback(result);
  return result;
}
.

Ora in koa ho bisogno di chiamare load e risposta json al client quindi uso questo codice qui sotto:

router= require('koa-router');
app = koa();
app.use(router(app));

app.get('load',loadjson);

function *loadJson(){
  var that = this;
  load(function(result){
    that.body = result;
  });
}
.

Ma ottengo questo errore:

_http_outgoing.js:331
throw new Error('Can\'t set headers after they are sent.');
      ^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:331:11)
at Object.module.exports.set (G:\NAP\node_modules\koa\lib\response.js:396:16)
at Object.length (G:\NAP\node_modules\koa\lib\response.js:178:10)
at Object.body (G:\NAP\node_modules\koa\lib\response.js:149:19)
at Object.body (G:\NAP\node_modules\koa\node_modules\delegates\index.js:91:31)
at G:\NAP\Server\OlapServer\index.js:40:19
at G:\NAP\Server\OlapServer\OLAPSchemaProvider.js:1599:9
at _LoadCubes.xmlaRequest.success   (G:\NAP\Server\OlapServer\OLAPSchemaProvider.js:1107:13)
at Object.Xmla._requestSuccess (G:\NAP\node_modules\xmla4js\src\Xmla.js:2113:50)
at Object.ajaxOptions.complete (G:\NAP\node_modules\xmla4js\src\Xmla.js:2024:34)
.

È stato utile?

Soluzione

Solo per chiarire le cose, scriviamo il tuo callback come

//Calback function
function load(callback){
    setTimeout(function() {
        var result = JSON.stringify({ 'my': 'json'});
        callback(/* error: */ null, result);
    }, 500);
}
.

In Koa World, questo è chiamato un thunk, il che significa che è una funzione asincrona che richiede solo un argomento: un callback con il prototipo (ERR, RES).Puoi controllare https://github.com/visionmedia/node-thunkify per una migliore spiegazione.

Ora devi scrivere il tuo middleware con

function *loadJson(){
  this.type = 'application/json';
  this.body = yield load;
}
.

Altri suggerimenti

Questo è dovuto principalmente perché KOA è basato su Generatore, se sulla parte superiore del middleware non supporta le callback.Quindi non sta aspettando la funzione finisca.La soluzione migliore sarebbe convertire la tua funzione in una promessa.Promessa funziona alla grande con Koa.

Ho avuto un problema molto simile usando Braintree (callback regolari) e KOA.Sulla base del codice, l'unica modifica di cui avevo bisogno era con la funzione di carico e come è stato chiamato.

router = require('koa-router');
app = koa();
app.use(router(app));

app.get('/load',loadjson);

function *loadJson(){
  this.body = yield load;
}

// Callback function
function load(callback) {
  // Prepare some data with xmla4js and ajax
  whatever_inputs = {...};
  final_method(whatever_inputs, callback);
}
.

La spiegazione di Jerome e Evan sopra è assolutamente corretta, e Thunkify sembra un processo adattoper farlo automaticamente.

Mentre i thunk erano una bella idea, a mio avviso un Promise è un approccio a lungo termine migliore. Molte biblioteche si stanno già spostando alle promesse per Async invece del vecchio standard del nodo callback(err, data), e sono morti semplici per avvolgere qualsiasi codice async per fare una promessa. Altri Devs avranno esperienze con le promesse e comprendono naturalmente il tuo codice, mentre la maggior parte dovrebbe cercare cosa sia un "Thunk".

E.G. Qui sto avvolgendo il jsedom non ancora e promesso, in una promessa, quindi posso cederlo nel mio generatore di koa.

const jsdom = require('node-jsdom');
const koa = require('koa');
const app = koa();
​
app.use(function *() {
  this.body = yield new Promise((resolve, reject) => jsdom.env({
    url: `http://example.org${this.url}`,
    done(errors, { document }) {
      if (errors) reject(errors.message);
      resolve(`<html>${document.body.outerHTML}</html>`);
    },
  }));
});
​
app.listen(2112);
.

Semanticamente, promesse e generatori vanno di pari passo per chiarire davvero il codice ASYNC. Un generatore può essere reinserito molte volte e produrre diversi valori, mentre una promessa significa "Prometto che avrò alcuni dati per te più tardi". Combinato, ottieni una delle cose più utili su KOA: la capacità di cedere sia promesse che valori sincroni.

Modifica: Ecco il tuo esempio originale avvolto con una promessa di tornare:

const router = require('koa-router');
const { load } = require('some-other-lib');
const app = koa();
app.use(router(app));

app.get('load', loadjson);

function* loadJson() {
  this.body = yield new Promise(resolve => {
    load(result => resolve(result));
  });
}
.

.

Per bypassare la gestione della risposta incorporata di KOA, è possibile impostare esplicitamente this.respond = false;.Utilizzare questo se si desidera scrivere all'oggetto res grezzo invece di lasciare che KOA maneggi la risposta per te.

Intestazione è già scritta dalla maneggevolezza di risposta incorporata prima che venga richiamata la callback.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top