首页 > 解决方案 > JavaScript。用户函数中的承诺。为什么它不起作用?

问题描述

任务:在主函数中,调用两个函数,其中第一个包含异步方法。

在 ReadValueBalances 函数中,once() 方法返回 Promise。然后我使用 then () 并返回结果。在此之后,应该启动第二个函数 UpdateValueMapBalances。

但是,为什么首先执行的是 UpdateValueMapBalances,而不是 ReadValueBalances?

    'use strict';

// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const FBfunctions = require('firebase-functions');

// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();




exports.UpdateBalancesUser = FBfunctions.database.ref('/{userID}/Movements').onWrite((MoveDataChange, context) => {
    const UserID = String(context.params.userID);   
    const BalanceRef = admin.database().ref('/'+ UserID +'/Balances') ;

    var Date_first, Date_last;
    var Value_first = 0; 
    var Value_last = 0;

    var TypeofChange = 0;
    MoveDataChange.after.forEach((childMove) => {
        if (!childMove.exists()) {
            console.log('MoveDataChange.after: нет!');
            //return false;  //выходим из функции
        }
        Date_last = childMove.child('dateInMilisec').val();
        Value_last = childMove.child("value").val()*childMove.child("kind").val();  
        console.log('Date_last: ', Date_last, '. Value_last: ', Value_last);
        TypeofChange = TypeofChange +1;
        //return true;
    });

    MoveDataChange.before.forEach((childMove) => {
        if (!childMove.exists()) {
            console.log('MoveDataChange.before: нет!');
            //return false;  //выходим из функции
        }
        Date_first = childMove.child('dateInMilisec').val();
        Value_first = -childMove.child("value").val()*childMove.child("kind").val();    //с обратным знаком, т.к. его не стало
        console.log('Date_first: ', Date_first, '. Value_first: ', Value_first);
        TypeofChange = TypeofChange - 1;
        //return true;
    });

    console.log('TypeofChange: ', TypeofChange);

    if (TypeofChange < 0) {             // удалили движение
        Date_last = Date_first; 
        Value_last = 0;             
    }
    if (TypeofChange > 0) {             // новое движение
        Date_first = Date_last; 
        Value_first = Value_last;
        Value_last = 0;         
    }

    if (Date_first > Date_last) {      //меняем местами
        let Date_tmp = Date_first;
        Date_first = Date_last;
        Date_last = Date_tmp;
        let Value_tmp = Value_first;
        Value_first = Value_last;
        Value_last = Value_tmp;
    }


    let BalanceMap = new Map;
    let BalanceMapUpdate = new Map;
    return ReadValueBalances(Date_first, BalanceRef)
        .then(UpdateValueMapBalances(BalanceMap, Date_first, Date_last, Value_first, Value_last))
        .then((BalanceMapUpdate)=>{
            return BalanceRef.update(BalanceMapUpdate, ()=>{
                console.log('Записали изменения ', BalanceMapUpdate);
            })
        }); 
});

function ReadValueBalances(Date_1, BalanceRef){  
    var BalancesMap = new Map;
    return BalanceRef.orderByKey().startAt(String(Date_1)).once('value')      // считываем значения БД после даты записи движения
        .then((DataSnapShot)=>{
            console.log('ReadValueBalances Получили выгрузку от ', Date_1);
            if (!DataSnapShot.exists()) {                                       // если после даты ничего, то считываем последнее значение до даты движения
                console.log('ReadValueBalances Получаем последнюю запись');                     
                return BalanceRef.orderByKey().endAt(String(Date_1)).limitToLast(1).once('value');                  
            } 
            else {
                console.log('ReadValueBalances Выгрузка есть');
                return DataSnapShot;
            }
        })
        .then((DataSnapShot)=>{         
            DataSnapShot.forEach((snapshot)=>{                  // цикл по элементам выгрузки. записываем в Map
                BalancesMap.set(snapshot.key, snapshot.val());
                console.log('snap key: ', snapshot.key, ' value:', snapshot.val());             
            });
            console.log('ReadValueBalances Закончили цикл');
            return BalancesMap;
        }); 
}


function UpdateValueMapBalances(BalanceMap_input, Date1, Date2, Delta1, Delta2){
    var BalanceMap_output = new Map;
    const Date_1 = new Date(Date1);
    const Date_2 = new Date(Date2); 
    console.log('UpdateValueMapBalances Date_1: ', Date_1, ' Date_2: ', Date_2);
    if (BalanceMap_input.size === 0) {
        console.log('UpdateValueMapBalances вх.коллекция пустая');
        var Date_item = new Date(Date_1);   
        console.log('UpdateValueMapBalances Date_item: ', Date_item);
        Date_item.setDate(1);
        Date_item.setMonth(Date_item.getMonth()+1);
        BalanceMap_output.set(Date_item.getMilliseconds(), Delta1);
        console.log('UpdateValueMapBalances BalanceMap_output: ', BalanceMap_output);
        return BalanceMap_output;
    }

    BalanceMap_input.forEach((ValueItem, KeyItem, MapItem)=>{
        console.log('ValueItem: ', ValueItem, ' KeyItem: ', KeyItem);   
        if (KeyItem <= Date1) {                 // возможно только в случае, если в выгрузке только 1 значение (до даты движения)
            console.log('UpdateValueMapBalances Дополняем коллекцию сверху');
            var bool_stop = false;
            var Date_item = new Date(KeyItem);                  
            Date_item.setDate(1); // на всякий случай
            console.log('Date_item ', Date_item);
            while (!bool_stop) {
                Date_item.setMonth(Date_item.getMonth()+1);
                if ((Date_item-Date_1) <= 0) {
                    BalanceMap_output.set(Date_item.getMilliseconds, ValueItem);    
                } else {
                    BalanceMap_output.set(Date_item.getMilliseconds, ValueItem + Delta1);  // в случае с удалением delta 1= -Value
                    bool_stop = true;
                }
            }
            console.log('UpdateValueMapBalances Дополнили коллекцию сверху');   
            return BalanceMap_output;  //TODO: выйти из цикла               
        } else {
            console.log('UpdateValueMapBalances Изменяем коллекцию снизу');             
            if (KeyItem <= Date2) {          // т.е. коллекция имеет значения после Date_first до Date_last. Срабатывает только если даты отличаются
                BalanceMap_output.set(KeyItem, ValueItem + Delta1);     
            } else {                                    // т.е. коллекция имеет значения после Date_last
                BalanceMap_output.set(KeyItem, ValueItem + Delta1 + Delta2);    // в случае с новым движением/удалением Delta2=0, а Delta1= -Value
            }
            console.log('UpdateValueMapBalances Изменили коллекцию снизу');
        }       
    })
    return BalanceMap_output;

日志:

2:23:26.362 PM
outlined_flag   
UpdateBalancesUser
Function execution took 1699 ms, finished with status: 'ok'
2:23:26.356 PM
info    
UpdateBalancesUser
Записали изменения Map { '1522540800000' => 200000 }
2:23:26.353 PM
info    
UpdateBalancesUser
ReadValueBalances Закончили цикл
2:23:26.353 PM
info    
UpdateBalancesUser
snap key: 1522540800000 value: 200000
2:23:26.353 PM
info    
UpdateBalancesUser
ReadValueBalances Выгрузка есть
2:23:26.352 PM
info    
UpdateBalancesUser
ReadValueBalances Получили выгрузку от 1519862400000
2:23:25.861 PM
info    
UpdateBalancesUser
UpdateValueMapBalances BalanceMap_output: Map { [Function: getMilliseconds] => -400000 }
2:23:25.860 PM
info    
UpdateBalancesUser
UpdateValueMapBalances Date_item: 2018-03-01T00:00:00.000Z
2:23:25.860 PM
info    
UpdateBalancesUser
UpdateValueMapBalances вх.коллекция пустая
2:23:25.860 PM
info    
UpdateBalancesUser
UpdateValueMapBalances Date_1: 2018-03-01T00:00:00.000Z Date_2: 2018-03-01T00:00:00.000Z
2:23:25.849 PM
info    
UpdateBalancesUser
TypeofChange: 0
2:23:25.849 PM
info    
UpdateBalancesUser
Date_first: 1519862400000 . Value_first: -400000

标签: javascriptfirebasefirebase-realtime-databasepromisegoogle-cloud-functions

解决方案


问题是这条线

 .then(UpdateValueMapBalances(BalanceMap, Date_first, Date_last, Value_first, Value_last))

分解它,then期望一个函数作为参数https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

但是发生的事情是您直接调用UpdateValueMapBalances,并且将其返回值用作参数then

这里写了一个稍微不同的方式来说明:

const successFunction = UpdateValueMapBalances(BalanceMap, Date_first, Date_last, Value_first, Value_last);

...


.then(successFunction)

假设您通过参数正确传递所有正确的数据,将函数调用包装在另一个函数中有望解决您的问题。这里有太多东西要我说。

.then(() => UpdateValueMapBalances(BalanceMap, Date_first, Date_last, Value_first, Value_last)

推荐阅读