简体   繁体   中英

How to call a Javascript function from Python

I have a python code (server side) which doesn't interact with client side. However, I need to represent some items when it (server code) will has done. The only idea I came up with is the JS function which represents an item, calling from Python. Could you advise me either packages or another idea to implement this.

Some Details (I do not aware is it necessary, but might be it's helpful)

async def start_delete_delay(app, delay):
    """
    The very function which thrust a delay for each front token.
    Key arguments:
    app -- our application.
    delay -- a delay in seconds
    """
    async with app['db'].acquire() as conn:

        # First of all we need to check for database emptiness
        query = text("SELECT True FROM tokens LIMIT(1)")
        if await conn.fetch(query):

            # If database is not empty then we are processing a waiting delay.
            # First, fetching an id & related token from the first position (due to it queue) from database.
            query = select([db.tokens.c.id, db.tokens.c.token]).order_by(asc(db.tokens.c.id)).limit(1)
            query_result = await conn.fetchrow(query)

            # Retrieving an id and token
            id_before_sleep, token = query_result['id'], query_result['token']

            # Setting a delay
            try:
                await asyncio.sleep(delay)

            # Some information related with cancellation error
            # https://docs.python.org/3/library/asyncio-task.html#asyncio.Task.cancel
            except asyncio.CancelledError:
                pass

            # Check whether a token at the first place as same as it was before
            finally:

                # If it possible but all of members picked their tokens over 60 seconds.
                if await conn.fetch(text("SELECT True FROM tokens LIMIT(1)")):
                    query_result = await conn.fetchrow(query)
                    id_after_sleep = query_result['id']

                    # If they are same then we delete that token and starting delay again.
                    if id_before_sleep == id_after_sleep:
                        query = delete(db.tokens).where(db.tokens.c.id == id_before_sleep)

                        # preparing a token for reuse.
                        app['new_token'].prepare_used_token(token)

                        # Deleting a token
                        await conn.fetchrow(query)

                        # I'd like to call a JS function (which I already have) here

                        # Starting a delay for adjacent token, over and over and over
                        task = make_task(start_delete_delay, app, delay)
                        asyncio.gather(task)

I found two solutions, so if someone faced with such problems try to use them:

First solution

The clue is WebSockets. I used aiohttp and asyncio .

In JavaScript file I added up a listening socket:

var socket = new WebSocket('/link-to-websocket')

In server-side I added a websocket_handler, in my case it sending the message after deleting a toke from database

async def websocket_handler(request):

    ws = web.WebSocketResponse()
    await ws.prepare(request)

    async for msg in ws:
        if msg.type == aiohttp.WSMsgType.TEXT:
            if app['updt_flag']:
                await ws.send_str("signal")
            else:
                await ws.close()
    return ws

And adding it to routes

app.add_routes([web.get('/link-to-websocket', websocket_handler)])

1) How JavaScript works: Deep dive into WebSockets and HTTP/2 with SSE + how to pick the right path

2) Python aiohttp websockets

However this method isn't the best, we don't use entire websocket's functionality therefore let's go ahead to another method: Server-Sent Events (SSE). This method is more suitable for the my problem because we always receiving response from server without request to it (whereas websockets doesn't incorporate such option):

Second solution As I said above I will use SSE and for these purposes it required a sse-package

pip install aiohttp_sse


import asyncio
from aiohttp_sse import sse_response


async def SSE_request(request):
    loop = request.app.loop
    async with sse_response(request) as resp:
        while True:
            if request.app['updt_flag']:
                await resp.send("signal")
                request.app['updt_flag'] = False
            await asyncio.sleep(1, loop=loop)
    return resp

Adding route

web.get('/update', SSE_request)

Adding listening sse to JS:

const evtSource = new EventSource("/update");
evtSource.onmessage = function(e) {
                    display_queue_remove();
}

Thats all:)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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