简体   繁体   English

如何合并几个MediaWiki API请求的结果?

[英]How to combine the results of several MediaWiki API requests?

I have a small (working) Wikipedia user script that queries the MediaWiki API and then queries it once again for each of the results of the first query, printing the results of the "second level" queries on the console (Firefox 52.0/Linux): 我有一个小型的(有效的)Wikipedia用户脚本,该脚本查询MediaWiki API,然后再次查询第一个查询的每个结果,并在控制台上打印“第二级”查询的结果(Firefox 52.0 / Linux) :

mw.loader.using( [ 'mediawiki.api', 'mediawiki.ForeignApi' ] ).done( function () {
    var api = new mw.Api();
    api.get( {
        action: 'query',
        meta: 'globaluserinfo',
        guiprop: 'merged'
    } ).done( function ( data ) {
        data.query.globaluserinfo.merged.forEach( function( element, index, array ) {
            let url = element.url;
            var remoteapi = new mw.ForeignApi( url + '/w/api.php' );
            [mw.config.get('wgNamespaceIds').user, mw.config.get('wgNamespaceIds').user_talk].forEach( function( element, index, array ) {
                remoteapi.get( {
                    action: 'query',
                    list: 'allpages',
                    apprefix: data.query.globaluserinfo.name,
                    apnamespace: element
                } ).done( function (data2) {
                    for( var j = 0; j < data2.query.allpages.length; j++ )
                        console.log( url + '/wiki/' + data2.query.allpages[j].title );
                });
            } );
        } );
    } );
} );

I now want to replace the individual console outputs with one combined dialog box (à la mw.loader.using( 'oojs-ui-windows' ).done( function () { OO.ui.alert( 'All results: ' + results ); } ); ). 我现在想用一个组合对话框替换单个控制台输出(àla mw.loader.using( 'oojs-ui-windows' ).done( function () { OO.ui.alert( 'All results: ' + results ); } ); )。

In other words, I want to execute one callback when all API queries have been done, accessing/aggregating/combining the results from all of them. 换句话说,我想在完成所有API查询后执行一个回调,以访问/汇总/合并所有查询的结果。 How can that be done? 那怎么办?

Parallel requests (same as Tim's answer, just a little more heavy on promises): 并行请求(与Tim的回答相同,只是对诺言的重视程度更高):

mw.loader.using( [ 'mediawiki.api', 'mediawiki.ForeignApi' ] ).done( function () {
    // get all accounts of user
    new mw.Api().get( {
        action: 'query',
        meta: 'globaluserinfo',
        guiprop: 'merged',
        formatversion: 2,
        errorformat: 'wikitext',
        errorsuselocal: true
    } )
    // create a list of needed requests
    .then( function ( data ) {
        return data.query.globaluserinfo.merged.map( function( element, index, array ) {
            let url = element.url;
            let remoteapi = ( url === 'https:' + mw.config.get( 'wgServer' ) )
                ? new mw.Api()
                : new mw.ForeignApi( url + '/w/api.php' );                if (url === 'https:' + mw.config.get('wgServer'));
            let request = {
                action: 'query',
                generator: 'allpages',
                gapprefix: data.query.globaluserinfo.name + '/',
                gaplimit: 'max',
                prop: 'info',
                inprop: 'url'
            };
            return [
                $.extend( { namespace: mw.config.get('wgNamespaceIds').user }, request ),
                $.extend( { namespace: mw.config.get('wgNamespaceIds').user_talk }, request )
            ];
        } );
    } )
    // fire the requests and merge promises
    .then( function ( requests ) {
        var promises = requests.map( function ( request ) {
            return remoteapi.get( request ).then( function ( data ) {
                return $.map( data.query.pages, function( val, key ) {
                    return val.fullurl;
                } );
            } ), function () {
                console.log( 'FAIL = ' + JSON.stringify( arguments ) );
            } );
        } );
        promises.push( mw.loader.using( 'oojs-ui-windows' ) );
        return $.when.apply( $, promises ).then( function ( urls ) {
            // last result is from mw.loader, discard it
            urls.pop();
            return urls;
        } );
    } )
    // business logic
    .done( function ( urls ) {
        OO.ui.alert( 'All results: ' + urls.join( '\n' ) );
    } ).fail( function () {
        OO.ui.alert( 'FAIL!' );
    } );
} );

If you want to limit parallelism (probably a good idea if you have many accounts) you can replace the "fire the requests" block with something like 如果您想限制并行性(如果您有许多帐户,可能是一个好主意),则可以使用以下方法替换“触发请求”块

.then( function ( requests ) {
    var status = Array( requests.length );
    let processNext = function () {
        let index = status.indexOf( undefined );
        if ( index >= 0 ) {
            status[index] = true;
            return remoteapi.get( requests[index] ).then( function ( data ) {
                requests[index] = $.map( data.query.pages, function( val, key ) {
                    return val.fullurl;
                } );
            } ), function () {
                console.log( 'FAIL = ' + JSON.stringify( arguments ) );
            } ).then( processNext, processNext );
        } else {
            return $.Deferred().resolve();
        }
    }
    let queue = Array( 5 ).map( function () {
        processNext();
    } ) );
    queue.push( mw.loader.using( 'oojs-ui-windows' ) );
    return $.when.apply( $, queue ).then( function () {
        return requests;
    } );
} )

(Note that I have done no testing whatsoever. Also, this does not handle continuation, which is too complex to attempt to write code for without testing. Maybe mw.Api does handle it, never checked. In any case, the limit is 500 page per wiki (5000 if you are a local admin) so you should probably be good.) (请注意,我没有做任何测试。此外,它不处理延续性,这太复杂了,以至于未经测试就无法尝试编写代码。也许mw.Api确实可以处理它,从未检查过。无论如何,限制为500每个Wiki的页面(如果您是本地管理员,则为5000),因此您应该不错。)

To wait until all queries have finished, the promises returned by mediawiki.api.get() need to be added to an array, in the following example p . 为了等待所有查询结束,需要将mediawiki.api.get()返回的promise添加到数组中,在以下示例中为p jQuery then offers the $.when() method to execute a callback when all promises given as parameters have been resolved. 然后,当所有作为参数给出的承诺都已解决时,jQuery提供$.when()方法来执行回调。 As the number of them in this case is random, $.when.apply() needs to be used. 由于这种情况下的数量是随机的, $.when.apply()需要使用$.when.apply()

mw.loader.using( [ 'mediawiki.api', 'mediawiki.ForeignApi' ] ).done( function () {
    var api = new mw.Api();
    api.get( {
        action: 'query',
        meta: 'globaluserinfo',
        guiprop: 'merged'
    } ).done( function ( data ) {
        var p = [];
        var r = [];
        data.query.globaluserinfo.merged.forEach( function( element, index, array ) {
            let url = element.url;
            if (url === 'https:' + mw.config.get('wgServer'))
                var remoteapi = new mw.Api();
            else
                var remoteapi = new mw.ForeignApi( url + '/w/api.php' );
            [mw.config.get('wgNamespaceIds').user, mw.config.get('wgNamespaceIds').user_talk].forEach( function( element, index, array ) {
                p.push( remoteapi.get( {
                    action: 'query',
                    list: 'allpages',
                    apprefix: data.query.globaluserinfo.name + '/',
                    apnamespace: element
                } ).done( function (data2) {
                    for( var j = 0; j < data2.query.allpages.length; j++ )
                        r.push( url + '/wiki/' + data2.query.allpages[j].title );
                } ).fail( function () {
                    console.log( 'FAIL = ' + JSON.stringify( arguments ) );
                } ) );
            } );
        } );
        $.when.apply($, p).done( function () {
            mw.loader.using( 'oojs-ui-windows' ).done( function () {
                OO.ui.alert( 'All results: ' + r );
            } );
        } ).fail( function () {
            mw.loader.using( 'oojs-ui-windows' ).done( function () {
                OO.ui.alert( 'FAIL!' );
            } );
        } );
    } );
} );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM