Pnpjs: Is there a clean way to set up a batch that depend on the result of another?

Created on 13 Mar 2019  路  3Comments  路  Source: pnp/pnpjs

Thank you for reporting an issue, suggesting an enhancement, or asking a question. We appreciate your feedback - to help the team understand your
needs please complete the below template to ensure we have the details to help. Thanks!

Please check out the Docs to see if your question is already addressed there. This will help us ensure our documentation covers the most frequent questions.

Category

  • [ ] Enhancement
  • [ ] Bug
  • [X] Question
  • [ ] Documentation gap/issue

Version

Please specify what version of the library you are using: [ 1.2.7 ]

Please specify what version(s) of SharePoint you are targeting: [ sp 2016 on-prem / SPFX 1.1.0 ]

If you are not using the latest release, please update and see if the issue is resolved before submitting an issue.

Expected / Desired Behavior / Question

Set up 3 batches:
1st: makes post, merge, and delete requests and pushes new IDs of posted items to an array
2nd: makes post, merge, and delete requests where some of the posts require the ID's of previous batch and also pushes the new ID's of the posted items to an array
3rd: makes post, merge, and delete requests where some of the posts require and ID value from both the 1st and 2nd batch results

The need for this comes from trying to keep established relationships via lookup fields in multiple lists.

Observed Behavior

I'm able to successfully set up the first two batches by using a value pushed to an array in the execute().then() portion of the 1st with a Promise.all() to execute the 2nd. The problem is trying to set up the 3rd batch and having it wait for both others to complete before making its calls. I realize this is less to do with the pnpjs library and more just fundamental coding but wanted to ask your advice and see if there is anything in the library set up for this situation.

If my explanation is confusing I can provide a code example that represents what I explained above.

Steps to Reproduce

Make 3 batches the 2nd and 3rd using the IDs from the previous batches.

Any feedback would be appreciated 馃槄 Thanks!

code answered question

Most helpful comment

@koltyakov Poetry in a post my friend. After taking your abstract and expanding it to save an array of results per type of call as well as splitting the chunks of dependent calls in to separate batches it works like a charm. I've read through most of the posts on batching that you and @patrick-rodgers have commented on and found a lot of great info. Thank you very much for the quick and helpful post! =)

All 3 comments

Hi @dharnen,

Please check the sample how this can be done:

import { sp } from '@pnp/sp';

interface Results {
    [key: string]: {
        data: any;
        error?: string;
    }
}

const wrapBatchPromise = <T>(promise: Promise<T>, res: Results, key: string): void => {
    res[key] = res[key] || { data: null };
    promise
        .then(data => {
            res[key].data = data;
        })
        .catch(error => {
            res[key].error = error.message;
        });
};

(async () => {

    const b = sp.web.createBatch();

    const res: Results = {};
    wrapBatchPromise(sp.web.select('Id,Title').inBatch(b).get(), res, 'req1');
    wrapBatchPromise(sp.web.lists.select('Id,Title').inBatch(b).get(), res, 'req2');

    await b.execute().catch(_ => { /**/ });

    // console.log({ res }); // contains req1 and req2 data or possible errors
    const errors = Object.keys(res)
        .filter(k => typeof res[k].error !== 'undefined')
        .map(k => res[k].error);
    if (errors.length > 0) {
        throw Error(`\n- ${errors.join('\n- ')}`);
    }

    wrapBatchPromise(
        sp.web.lists.select('Id,Title')
            .filter(`Title eq '${res['req2'].data[0].Title}'`)
            .inBatch(b).get(),
        res, 'req3'
    );

    await b.execute().catch(_ => { /**/ });

    return res;

})()
    .then(console.log)
    .catch(console.warn);

image

The sample is abstract. Just artificial requests in one batch and data usage in the second batch.

image

wrapBatchPromise shows the idea of how to deal with results and error returned by batch API.

Depending on errors processing strategy, one can collect all possible errors or wrap the logic on the first one by removing empty catch in await b.execute().catch(_ => { /**/ });.

Great answer @koltyakov!

@koltyakov Poetry in a post my friend. After taking your abstract and expanding it to save an array of results per type of call as well as splitting the chunks of dependent calls in to separate batches it works like a charm. I've read through most of the posts on batching that you and @patrick-rodgers have commented on and found a lot of great info. Thank you very much for the quick and helpful post! =)

Was this page helpful?
0 / 5 - 0 ratings