Vyhledávání na webu

javascript - CosmosDB uložené procedury - promise místo callbacku


Je možné použít JavaScriptové promises místo běžných callbacků v rámci volání API uložených procedur CosmosDB (DocumentDB)? Příkladem použití by byla implementace stránkování.

Například

token = getToken();
doSomething(token);    

//....
function getToken(....) {   

  //...
  collection.queryDocuments(link, query, queryOptions, function(error, documents, responseOptions) {
    return responseOptions.continuation;
  });
}

nebude fungovat, protože token je vrácen v rámci callbacku a provádění pokračuje. Mohl byste prosím uvést příklad, jak byste to implementoval?

Odpověď č. 1

Verze ECMAScript, na kterou se odkazuje dokumentace Cosmos DB, podporuje async/await a Promises. Oba tyto prvky mohu používat ve svých uložených procedurách.

Zde je funkce, která vrací promise, která provádí parametrizovaný dotaz na dokument:

function queryDocumentsAsync(sql, parameters, options) {
    const querySpec = {
        query: sql,
        parameters: parameters
    };

    return new Promise((resolve, reject)=>{
        let isAccepted = __.queryDocuments(__.getSelfLink(), querySpec, options || {}, (err, feed, options) => {
            if(err) reject(err);
            resolve({
                feed: feed,
                options: options
            });
        });
        if(!isAccepted) throw "Query was not accepted.";
    });
}

Vidím však určitá omezení při vynucování návratu zpět tímto přístupem. Pokud vyhodíte chybu, je pohlcena řetězcem promise a nikdy se ven nedostane.

Odpověď č. 2

Zde je příklad, jak použít async await pro scénář dotazu a nahrazení.

function async_sample() {
    const ERROR_CODE = {
        NotAccepted: 429
    };

    const asyncHelper = {
        queryDocuments(sqlQuery, options) {
            return new Promise((resolve, reject) => {
                const isAccepted = __.queryDocuments(__.getSelfLink(), sqlQuery, options, (err, feed, options) => {
                    if (err) reject(err);
                    resolve({ feed, options });
                });
                if (!isAccepted) reject(new Error(ERROR_CODE.NotAccepted, "replaceDocument was not accepted."));
            });
        },

        replaceDocument(doc) {
            return new Promise((resolve, reject) => {
                const isAccepted = __.replaceDocument(doc._self, doc, (err, result, options) => {
                    if (err) reject(err);
                    resolve({ result, options });
                });
                if (!isAccepted) reject(new Error(ERROR_CODE.NotAccepted, "replaceDocument was not accepted."));
            });
        }
    };

    async function main() {
        let continuation;
        do {
            let { feed, options } = await asyncHelper.queryDocuments("SELECT * from c", { continuation });

            for (let doc of feed) {
                doc.newProp = 1;
                await asyncHelper.replaceDocument(doc);
            }

            continuation = options.continuation;
        } while (continuation);
    }

    main().catch(err => getContext().abort(err));
}